feat(cli): show raw reasoning content

This commit is contained in:
aibrahim-oai
2025-07-13 23:39:56 -07:00
parent c46bb67d77
commit caab634c57
9 changed files with 85 additions and 5 deletions
+10
View File
@@ -452,6 +452,16 @@ Setting `hide_agent_reasoning` to `true` suppresses these events in **both** the
hide_agent_reasoning = true # defaults to false
```
## show_reasoning_content
When enabled, Codex will display the raw chain-of-thought text returned by the
model for reasoning events. This content is not moderated and may contain
hallucinations or other undesirable text, so it is disabled by default.
```toml
show_reasoning_content = true # defaults to false
```
## model_context_window
The size of the context window for the model, in tokens.
+13 -1
View File
@@ -56,12 +56,14 @@ use crate::mcp_tool_call::handle_mcp_tool_call;
use crate::models::ContentItem;
use crate::models::FunctionCallOutputPayload;
use crate::models::LocalShellAction;
use crate::models::ReasoningItemContent;
use crate::models::ReasoningItemReasoningSummary;
use crate::models::ResponseInputItem;
use crate::models::ResponseItem;
use crate::models::ShellToolCallParams;
use crate::project_doc::get_user_instructions;
use crate::protocol::AgentMessageEvent;
use crate::protocol::AgentReasoningContentEvent;
use crate::protocol::AgentReasoningEvent;
use crate::protocol::ApplyPatchApprovalRequestEvent;
use crate::protocol::AskForApproval;
@@ -1196,7 +1198,7 @@ async fn handle_response_item(
}
None
}
ResponseItem::Reasoning { id: _, summary } => {
ResponseItem::Reasoning { id: _, summary, content } => {
for item in summary {
let text = match item {
ReasoningItemReasoningSummary::SummaryText { text } => text,
@@ -1207,6 +1209,16 @@ async fn handle_response_item(
};
sess.tx_event.send(event).await.ok();
}
for item in content {
let text = match item {
ReasoningItemContent::ReasoningText { text } => text,
};
let event = Event {
id: sub_id.to_string(),
msg: EventMsg::AgentReasoningContent(AgentReasoningContentEvent { text }),
};
sess.tx_event.send(event).await.ok();
}
None
}
ResponseItem::FunctionCall {
+12
View File
@@ -57,6 +57,10 @@ pub struct Config {
/// users are only interested in the final agent responses.
pub hide_agent_reasoning: bool,
/// When `true`, the raw chain-of-thought text from reasoning events will be
/// displayed in the UI in addition to the reasoning summaries.
pub show_reasoning_content: 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).
@@ -313,6 +317,10 @@ pub struct ConfigToml {
/// UI/output. Defaults to `false`.
pub hide_agent_reasoning: Option<bool>,
/// When set to `true`, raw chain-of-thought text from reasoning events will
/// be shown in the UI.
pub show_reasoning_content: Option<bool>,
pub model_reasoning_effort: Option<ReasoningEffort>,
pub model_reasoning_summary: Option<ReasoningSummary>,
@@ -477,6 +485,7 @@ impl Config {
codex_linux_sandbox_exe,
hide_agent_reasoning: cfg.hide_agent_reasoning.unwrap_or(false),
show_reasoning_content: cfg.show_reasoning_content.unwrap_or(false),
model_reasoning_effort: config_profile
.model_reasoning_effort
.or(cfg.model_reasoning_effort)
@@ -796,6 +805,7 @@ disable_response_storage = true
tui: Tui::default(),
codex_linux_sandbox_exe: None,
hide_agent_reasoning: false,
show_reasoning_content: false,
model_reasoning_effort: ReasoningEffort::High,
model_reasoning_summary: ReasoningSummary::Detailed,
model_supports_reasoning_summaries: false,
@@ -842,6 +852,7 @@ disable_response_storage = true
tui: Tui::default(),
codex_linux_sandbox_exe: None,
hide_agent_reasoning: false,
show_reasoning_content: false,
model_reasoning_effort: ReasoningEffort::default(),
model_reasoning_summary: ReasoningSummary::default(),
model_supports_reasoning_summaries: false,
@@ -903,6 +914,7 @@ disable_response_storage = true
tui: Tui::default(),
codex_linux_sandbox_exe: None,
hide_agent_reasoning: false,
show_reasoning_content: false,
model_reasoning_effort: ReasoningEffort::default(),
model_reasoning_summary: ReasoningSummary::default(),
model_supports_reasoning_summaries: false,
+8
View File
@@ -43,6 +43,8 @@ pub enum ResponseItem {
Reasoning {
id: String,
summary: Vec<ReasoningItemReasoningSummary>,
#[serde(default)]
content: Vec<ReasoningItemContent>,
},
LocalShellCall {
/// Set when using the chat completions API.
@@ -128,6 +130,12 @@ pub enum ReasoningItemReasoningSummary {
SummaryText { text: String },
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ReasoningItemContent {
ReasoningText { text: String },
}
impl From<Vec<InputItem>> for ResponseInputItem {
fn from(items: Vec<InputItem>) -> Self {
Self::Message {
+9 -1
View File
@@ -282,9 +282,12 @@ pub enum EventMsg {
/// Agent text output message
AgentMessage(AgentMessageEvent),
/// Reasoning event from agent.
/// Reasoning summary from agent.
AgentReasoning(AgentReasoningEvent),
/// Raw chain-of-thought from agent.
AgentReasoningContent(AgentReasoningContentEvent),
/// Ack the client's configure message.
SessionConfigured(SessionConfiguredEvent),
@@ -345,6 +348,11 @@ pub struct AgentReasoningEvent {
pub text: String,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct AgentReasoningContentEvent {
pub text: String,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct McpToolCallBeginEvent {
/// Identifier so this can be paired with the McpToolCallEnd event.
+19 -1
View File
@@ -15,6 +15,7 @@ use codex_core::protocol::McpToolCallBeginEvent;
use codex_core::protocol::McpToolCallEndEvent;
use codex_core::protocol::PatchApplyBeginEvent;
use codex_core::protocol::PatchApplyEndEvent;
use codex_core::protocol::AgentReasoningContentEvent;
use codex_core::protocol::SessionConfiguredEvent;
use codex_core::protocol::TokenUsage;
use owo_colors::OwoColorize;
@@ -50,10 +51,15 @@ pub(crate) struct EventProcessor {
/// Whether to include `AgentReasoning` events in the output.
show_agent_reasoning: bool,
show_agent_reasoning_content: bool,
}
impl EventProcessor {
pub(crate) fn create_with_ansi(with_ansi: bool, show_agent_reasoning: bool) -> Self {
pub(crate) fn create_with_ansi(
with_ansi: bool,
show_agent_reasoning: bool,
show_agent_reasoning_content: bool,
) -> Self {
let call_id_to_command = HashMap::new();
let call_id_to_patch = HashMap::new();
let call_id_to_tool_call = HashMap::new();
@@ -71,6 +77,7 @@ impl EventProcessor {
cyan: Style::new().cyan(),
call_id_to_tool_call,
show_agent_reasoning,
show_agent_reasoning_content,
}
} else {
Self {
@@ -85,6 +92,7 @@ impl EventProcessor {
cyan: Style::new(),
call_id_to_tool_call,
show_agent_reasoning,
show_agent_reasoning_content,
}
}
}
@@ -449,6 +457,16 @@ impl EventProcessor {
);
}
}
EventMsg::AgentReasoningContent(agent_reasoning_event) => {
if self.show_agent_reasoning && self.show_agent_reasoning_content {
ts_println!(
self,
"{}\n{}",
"thinking".style(self.italic).style(self.magenta),
agent_reasoning_event.text
);
}
}
EventMsg::SessionConfigured(session_configured_event) => {
let SessionConfiguredEvent {
session_id,
+5 -2
View File
@@ -115,8 +115,11 @@ 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 mut event_processor =
EventProcessor::create_with_ansi(stdout_with_ansi, !config.hide_agent_reasoning);
let mut event_processor = EventProcessor::create_with_ansi(
stdout_with_ansi,
!config.hide_agent_reasoning,
config.show_reasoning_content,
);
// Print the effective configuration and prompt so users can see what Codex
// is using.
event_processor.print_config_summary(&config, &prompt);
@@ -175,6 +175,7 @@ pub async fn run_codex_tool_session(
| EventMsg::TaskStarted
| EventMsg::TokenCount(_)
| EventMsg::AgentReasoning(_)
| EventMsg::AgentReasoningContent(_)
| EventMsg::McpToolCallBegin(_)
| EventMsg::McpToolCallEnd(_)
| EventMsg::ExecCommandBegin(_)
+8
View File
@@ -4,6 +4,7 @@ use std::sync::Arc;
use codex_core::codex_wrapper::init_codex;
use codex_core::config::Config;
use codex_core::protocol::AgentMessageEvent;
use codex_core::protocol::AgentReasoningContentEvent;
use codex_core::protocol::AgentReasoningEvent;
use codex_core::protocol::ApplyPatchApprovalRequestEvent;
use codex_core::protocol::ErrorEvent;
@@ -251,6 +252,13 @@ impl ChatWidget<'_> {
self.request_redraw();
}
}
EventMsg::AgentReasoningContent(AgentReasoningContentEvent { text }) => {
if !self.config.hide_agent_reasoning && self.config.show_reasoning_content {
self.conversation_history
.add_agent_reasoning(&self.config, text);
self.request_redraw();
}
}
EventMsg::TaskStarted => {
self.bottom_pane.clear_ctrl_c_quit_hint();
self.bottom_pane.set_task_running(true);