feat: include "reasoning" messages in Rust TUI (#892)

As shown in the screenshot, we now include reasoning messages from the
model in the TUI under the heading "codex reasoning":


![image](https://github.com/user-attachments/assets/d8eb3dc3-2f9f-4e95-847e-d24b421249a8)

To ensure these are visible by default when using `o4-mini`, this also
changes the default value for `summary` (formerly `generate_summary`,
which is deprecated in favor of `summary` according to the docs) from
unset to `"auto"`.
This commit is contained in:
Michael Bolin
2025-05-10 21:43:27 -07:00
committed by GitHub
parent 2b122da087
commit b4785b5f88
9 changed files with 65 additions and 3 deletions

View File

@@ -26,6 +26,7 @@ use crate::client_common::Prompt;
use crate::client_common::Reasoning;
use crate::client_common::ResponseEvent;
use crate::client_common::ResponseStream;
use crate::client_common::Summary;
use crate::error::CodexErr;
use crate::error::Result;
use crate::flags::CODEX_RS_SSE_FIXTURE;
@@ -173,7 +174,7 @@ impl ModelClient {
parallel_tool_calls: false,
reasoning: Some(Reasoning {
effort: "high",
generate_summary: None,
summary: Some(Summary::Auto),
}),
previous_response_id: prompt.prev_id.clone(),
store: prompt.store,

View File

@@ -36,7 +36,19 @@ pub enum ResponseEvent {
pub(crate) struct Reasoning {
pub(crate) effort: &'static str,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) generate_summary: Option<bool>,
pub(crate) summary: Option<Summary>,
}
/// A summary of the reasoning performed by the model. This can be useful for
/// debugging and understanding the model's reasoning process.
#[derive(Debug, Serialize)]
#[serde(rename_all = "lowercase")]
pub(crate) enum Summary {
Auto,
#[allow(dead_code)] // Will go away once this is configurable.
Concise,
#[allow(dead_code)] // Will go away once this is configurable.
Detailed,
}
#[derive(Debug, Serialize)]

View File

@@ -49,6 +49,7 @@ use crate::mcp_connection_manager::try_parse_fully_qualified_tool_name;
use crate::mcp_tool_call::handle_mcp_tool_call;
use crate::models::ContentItem;
use crate::models::FunctionCallOutputPayload;
use crate::models::ReasoningItemReasoningSummary;
use crate::models::ResponseInputItem;
use crate::models::ResponseItem;
use crate::models::ShellToolCallParams;
@@ -934,6 +935,18 @@ async fn handle_response_item(
}
}
}
ResponseItem::Reasoning { id: _, summary } => {
for item in summary {
let text = match item {
ReasoningItemReasoningSummary::SummaryText { text } => text,
};
let event = Event {
id: sub_id.to_string(),
msg: EventMsg::AgentReasoning { text },
};
sess.tx_event.send(event).await.ok();
}
}
ResponseItem::FunctionCall {
name,
arguments,

View File

@@ -33,6 +33,10 @@ pub enum ResponseItem {
role: String,
content: Vec<ContentItem>,
},
Reasoning {
id: String,
summary: Vec<ReasoningItemReasoningSummary>,
},
FunctionCall {
name: String,
// The Responses API returns the function call arguments as a *string* that contains
@@ -67,6 +71,12 @@ impl From<ResponseInputItem> for ResponseItem {
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ReasoningItemReasoningSummary {
SummaryText { text: String },
}
impl From<Vec<InputItem>> for ResponseInputItem {
fn from(items: Vec<InputItem>) -> Self {
Self::Message {

View File

@@ -317,6 +317,11 @@ pub enum EventMsg {
message: String,
},
/// Reasoning event from agent.
AgentReasoning {
text: String,
},
/// Ack the client's configure message.
SessionConfigured {
/// Tell the client what model is being queried.

View File

@@ -114,7 +114,7 @@ impl RolloutRecorder {
ResponseItem::Message { .. }
| ResponseItem::FunctionCall { .. }
| ResponseItem::FunctionCallOutput { .. } => {}
ResponseItem::Other => {
ResponseItem::Reasoning { .. } | ResponseItem::Other => {
// These should never be serialized.
continue;
}