From 6576c6292cb39aee149348b8aaa8b6a50f7450bd Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Fri, 30 May 2025 23:11:54 -0700 Subject: [PATCH] feat: add hide_agent_reasoning config option --- codex-rs/config.md | 10 ++++++++++ codex-rs/core/src/config.rs | 14 ++++++++++++++ codex-rs/exec/src/event_processor.rs | 21 ++++++++++++++------- codex-rs/exec/src/lib.rs | 3 ++- codex-rs/tui/src/chatwidget.rs | 8 +++++--- 5 files changed, 45 insertions(+), 11 deletions(-) diff --git a/codex-rs/config.md b/codex-rs/config.md index a1caacfcbc..416eeb4144 100644 --- a/codex-rs/config.md +++ b/codex-rs/config.md @@ -354,6 +354,16 @@ Note this is **not** a general editor setting (like `$EDITOR`), as it only accep Currently, `"vscode"` is the default, though Codex does not verify VS Code is installed. As such, `file_opener` may default to `"none"` or something else in the future. +## hide_agent_reasoning + +Codex intermittently emits "reasoning" events that show the model’s internal "thinking" before it produces a final answer. Some users may find these events distracting, especially in CI logs or minimal terminal output. + +Setting `hide_agent_reasoning` to `true` suppresses these events in **both** the TUI as well as the headless `exec` sub-command: + +```toml +hide_agent_reasoning = true # defaults to false +``` + ## project_doc_max_bytes Maximum number of bytes to read from an `AGENTS.md` file to include in the instructions sent with the first turn of a session. Defaults to 32 KiB. diff --git a/codex-rs/core/src/config.rs b/codex-rs/core/src/config.rs index b6871da153..d948ddb916 100644 --- a/codex-rs/core/src/config.rs +++ b/codex-rs/core/src/config.rs @@ -42,6 +42,11 @@ pub struct Config { pub shell_environment_policy: ShellEnvironmentPolicy, + /// When `true`, `AgentReasoning` events emitted by the backend will be + /// suppressed from the frontend output. This can reduce visual noise when + /// users are only interested in the final agent responses. + pub hide_agent_reasoning: bool, + /// Disable server-side response storage (sends the full conversation /// context with every request). Currently necessary for OpenAI customers /// who have opted into Zero Data Retention (ZDR). @@ -272,6 +277,10 @@ pub struct ConfigToml { /// Collection of settings that are specific to the TUI. pub tui: Option, + + /// When set to `true`, `AgentReasoning` events will be hidden from the + /// UI/output. Defaults to `false`. + pub hide_agent_reasoning: Option, } fn deserialize_sandbox_permissions<'de, D>( @@ -433,6 +442,8 @@ impl Config { file_opener: cfg.file_opener.unwrap_or(UriBasedFileOpener::VsCode), tui: cfg.tui.unwrap_or_default(), codex_linux_sandbox_exe, + + hide_agent_reasoning: cfg.hide_agent_reasoning.unwrap_or(false), }; Ok(config) } @@ -774,6 +785,7 @@ disable_response_storage = true file_opener: UriBasedFileOpener::VsCode, tui: Tui::default(), codex_linux_sandbox_exe: None, + hide_agent_reasoning: false, }, o3_profile_config ); @@ -813,6 +825,7 @@ disable_response_storage = true file_opener: UriBasedFileOpener::VsCode, tui: Tui::default(), codex_linux_sandbox_exe: None, + hide_agent_reasoning: false, }; assert_eq!(expected_gpt3_profile_config, gpt3_profile_config); @@ -867,6 +880,7 @@ disable_response_storage = true file_opener: UriBasedFileOpener::VsCode, tui: Tui::default(), codex_linux_sandbox_exe: None, + hide_agent_reasoning: false, }; assert_eq!(expected_zdr_profile_config, zdr_profile_config); diff --git a/codex-rs/exec/src/event_processor.rs b/codex-rs/exec/src/event_processor.rs index 57a6cbc9ac..89ad7d7cde 100644 --- a/codex-rs/exec/src/event_processor.rs +++ b/codex-rs/exec/src/event_processor.rs @@ -43,10 +43,13 @@ pub(crate) struct EventProcessor { red: Style, green: Style, cyan: Style, + + /// Whether to include `AgentReasoning` events in the output. + show_agent_reasoning: bool, } impl EventProcessor { - pub(crate) fn create_with_ansi(with_ansi: bool) -> Self { + pub(crate) fn create_with_ansi(with_ansi: bool, show_agent_reasoning: bool) -> Self { let call_id_to_command = HashMap::new(); let call_id_to_patch = HashMap::new(); let call_id_to_tool_call = HashMap::new(); @@ -63,6 +66,7 @@ impl EventProcessor { green: Style::new().green(), cyan: Style::new().cyan(), call_id_to_tool_call, + show_agent_reasoning, } } else { Self { @@ -76,6 +80,7 @@ impl EventProcessor { green: Style::new(), cyan: Style::new(), call_id_to_tool_call, + show_agent_reasoning, } } } @@ -411,12 +416,14 @@ impl EventProcessor { // Should we exit? } EventMsg::AgentReasoning(agent_reasoning_event) => { - ts_println!( - self, - "{}\n{}", - "thinking".style(self.italic).style(self.magenta), - agent_reasoning_event.text - ); + if self.show_agent_reasoning { + ts_println!( + self, + "{}\n{}", + "thinking".style(self.italic).style(self.magenta), + agent_reasoning_event.text + ); + } } EventMsg::SessionConfigured(session_configured_event) => { let SessionConfiguredEvent { diff --git a/codex-rs/exec/src/lib.rs b/codex-rs/exec/src/lib.rs index e203c2f161..925e25d670 100644 --- a/codex-rs/exec/src/lib.rs +++ b/codex-rs/exec/src/lib.rs @@ -112,7 +112,8 @@ pub async fn run_main(cli: Cli, codex_linux_sandbox_exe: Option) -> any }; let config = Config::load_with_cli_overrides(cli_kv_overrides, overrides)?; - let mut event_processor = EventProcessor::create_with_ansi(stdout_with_ansi); + let mut event_processor = + EventProcessor::create_with_ansi(stdout_with_ansi, !config.hide_agent_reasoning); // Print the effective configuration and prompt so users can see what Codex // is using. event_processor.print_config_summary(&config, &prompt); diff --git a/codex-rs/tui/src/chatwidget.rs b/codex-rs/tui/src/chatwidget.rs index 4819be3809..63f3bc727a 100644 --- a/codex-rs/tui/src/chatwidget.rs +++ b/codex-rs/tui/src/chatwidget.rs @@ -239,9 +239,11 @@ impl ChatWidget<'_> { self.request_redraw(); } EventMsg::AgentReasoning(AgentReasoningEvent { text }) => { - self.conversation_history - .add_agent_reasoning(&self.config, text); - self.request_redraw(); + if !self.config.hide_agent_reasoning { + self.conversation_history + .add_agent_reasoning(&self.config, text); + self.request_redraw(); + } } EventMsg::TaskStarted => { self.bottom_pane.set_task_running(true);