feat: add hide_agent_reasoning config option (#1181)

This PR introduces a `hide_agent_reasoning` config option (that defaults
to `false`) that users can enable to make the output less verbose by
suppressing reasoning output.

To test, verified that this includes agent reasoning in the output:

```
echo hello | just exec
```

whereas this does not:

```
echo hello | just exec --config hide_agent_reasoning=false
```
This commit is contained in:
Michael Bolin
2025-05-30 23:14:56 -07:00
committed by GitHub
parent 4f3d294762
commit e81327e5f4
5 changed files with 45 additions and 11 deletions

View File

@@ -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. 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 models 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 ## 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. 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.

View File

@@ -42,6 +42,11 @@ pub struct Config {
pub shell_environment_policy: ShellEnvironmentPolicy, 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 /// Disable server-side response storage (sends the full conversation
/// context with every request). Currently necessary for OpenAI customers /// context with every request). Currently necessary for OpenAI customers
/// who have opted into Zero Data Retention (ZDR). /// who have opted into Zero Data Retention (ZDR).
@@ -272,6 +277,10 @@ pub struct ConfigToml {
/// Collection of settings that are specific to the TUI. /// Collection of settings that are specific to the TUI.
pub tui: Option<Tui>, pub tui: Option<Tui>,
/// When set to `true`, `AgentReasoning` events will be hidden from the
/// UI/output. Defaults to `false`.
pub hide_agent_reasoning: Option<bool>,
} }
fn deserialize_sandbox_permissions<'de, D>( fn deserialize_sandbox_permissions<'de, D>(
@@ -433,6 +442,8 @@ impl Config {
file_opener: cfg.file_opener.unwrap_or(UriBasedFileOpener::VsCode), file_opener: cfg.file_opener.unwrap_or(UriBasedFileOpener::VsCode),
tui: cfg.tui.unwrap_or_default(), tui: cfg.tui.unwrap_or_default(),
codex_linux_sandbox_exe, codex_linux_sandbox_exe,
hide_agent_reasoning: cfg.hide_agent_reasoning.unwrap_or(false),
}; };
Ok(config) Ok(config)
} }
@@ -774,6 +785,7 @@ disable_response_storage = true
file_opener: UriBasedFileOpener::VsCode, file_opener: UriBasedFileOpener::VsCode,
tui: Tui::default(), tui: Tui::default(),
codex_linux_sandbox_exe: None, codex_linux_sandbox_exe: None,
hide_agent_reasoning: false,
}, },
o3_profile_config o3_profile_config
); );
@@ -813,6 +825,7 @@ disable_response_storage = true
file_opener: UriBasedFileOpener::VsCode, file_opener: UriBasedFileOpener::VsCode,
tui: Tui::default(), tui: Tui::default(),
codex_linux_sandbox_exe: None, codex_linux_sandbox_exe: None,
hide_agent_reasoning: false,
}; };
assert_eq!(expected_gpt3_profile_config, gpt3_profile_config); assert_eq!(expected_gpt3_profile_config, gpt3_profile_config);
@@ -867,6 +880,7 @@ disable_response_storage = true
file_opener: UriBasedFileOpener::VsCode, file_opener: UriBasedFileOpener::VsCode,
tui: Tui::default(), tui: Tui::default(),
codex_linux_sandbox_exe: None, codex_linux_sandbox_exe: None,
hide_agent_reasoning: false,
}; };
assert_eq!(expected_zdr_profile_config, zdr_profile_config); assert_eq!(expected_zdr_profile_config, zdr_profile_config);

View File

@@ -43,10 +43,13 @@ pub(crate) struct EventProcessor {
red: Style, red: Style,
green: Style, green: Style,
cyan: Style, cyan: Style,
/// Whether to include `AgentReasoning` events in the output.
show_agent_reasoning: bool,
} }
impl EventProcessor { 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_command = HashMap::new();
let call_id_to_patch = HashMap::new(); let call_id_to_patch = HashMap::new();
let call_id_to_tool_call = HashMap::new(); let call_id_to_tool_call = HashMap::new();
@@ -63,6 +66,7 @@ impl EventProcessor {
green: Style::new().green(), green: Style::new().green(),
cyan: Style::new().cyan(), cyan: Style::new().cyan(),
call_id_to_tool_call, call_id_to_tool_call,
show_agent_reasoning,
} }
} else { } else {
Self { Self {
@@ -76,6 +80,7 @@ impl EventProcessor {
green: Style::new(), green: Style::new(),
cyan: Style::new(), cyan: Style::new(),
call_id_to_tool_call, call_id_to_tool_call,
show_agent_reasoning,
} }
} }
} }
@@ -411,12 +416,14 @@ impl EventProcessor {
// Should we exit? // Should we exit?
} }
EventMsg::AgentReasoning(agent_reasoning_event) => { EventMsg::AgentReasoning(agent_reasoning_event) => {
ts_println!( if self.show_agent_reasoning {
self, ts_println!(
"{}\n{}", self,
"thinking".style(self.italic).style(self.magenta), "{}\n{}",
agent_reasoning_event.text "thinking".style(self.italic).style(self.magenta),
); agent_reasoning_event.text
);
}
} }
EventMsg::SessionConfigured(session_configured_event) => { EventMsg::SessionConfigured(session_configured_event) => {
let SessionConfiguredEvent { let SessionConfiguredEvent {

View File

@@ -112,7 +112,8 @@ pub async fn run_main(cli: Cli, codex_linux_sandbox_exe: Option<PathBuf>) -> any
}; };
let config = Config::load_with_cli_overrides(cli_kv_overrides, overrides)?; 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 // Print the effective configuration and prompt so users can see what Codex
// is using. // is using.
event_processor.print_config_summary(&config, &prompt); event_processor.print_config_summary(&config, &prompt);

View File

@@ -239,9 +239,11 @@ impl ChatWidget<'_> {
self.request_redraw(); self.request_redraw();
} }
EventMsg::AgentReasoning(AgentReasoningEvent { text }) => { EventMsg::AgentReasoning(AgentReasoningEvent { text }) => {
self.conversation_history if !self.config.hide_agent_reasoning {
.add_agent_reasoning(&self.config, text); self.conversation_history
self.request_redraw(); .add_agent_reasoning(&self.config, text);
self.request_redraw();
}
} }
EventMsg::TaskStarted => { EventMsg::TaskStarted => {
self.bottom_pane.set_task_running(true); self.bottom_pane.set_task_running(true);