openai / openai/codex

TUI: let users keep completed reasoning summaries in the main conversation

Open
#46,356 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

CLI config enhancement TUI
Dominant language
Rust
Stars
125k
Forks
19.4k
PR merge metrics
PR metrics pending

Description

In Codex CLI 0.155.0, the live reasoning summary is presented as one changing activity line. At a typical terminal width, a long line is cut off with an ellipsis, sometimes before it communicates the point. When the block finishes, its full summary is available in the expanded transcript, but the main conversation has no persistent copy. Following a long task now means repeatedly opening another view to read what Codex just considered.

Could the TUI offer an opt-in way to keep completed reasoning summaries in the main conversation? This would give people who use the main view as a readable record of progress the 0.154.0 behavior, while preserving the new presentation as the default.

What changed

At 0.154.0 (6b9826e), eligible completed summary blocks were displayed in the main conversation. The code set transcript_only conditionally. At 0.155.0 (f0a1b8f), every completed block is created with transcript_only = true. PR #43921 describes this as an intentional move to the status row and expanded transcript.

This is about where generated summaries appear. The documented model_reasoning_summary setting controls the summary's detail, and tui.status_line configures the separate footer. I could not find a documented setting that restores main-conversation placement. The older TUI did not stream every reasoning delta into main history; it showed eligible completed blocks. That is the behavior requested here.

How to see it

Run the 0.154.0 and 0.155.0 TUI binaries separately at the same terminal width, verifying each binary's version using that binary's own path before launching it. Use a model and task that produce a multiline reasoning summary. In 0.155.0, watch the live activity line shorten at a narrow width, then compare the main conversation with the expanded transcript once the block finishes. In 0.154.0, eligible completed blocks remain visible in the main conversation. Checking codex --version in a different shell does not establish which binary an already running TUI pane uses.

The source change above establishes the completed-block placement. I have seen the cropped activity line in the TUI, but have not captured a controlled, version-bound side-by-side recording. Whether any particular model emits a multiline summary is also model and task dependent.

The two views below use the same illustrative turn at the same width. The labels identify the kinds of content; they are annotations, not text Codex prints. The live status row appears while the model is working. The older inline block appears when an eligible reasoning block finishes.

Current 0.155.0 main view:

+-------------------------------------------------------------------+
| USER MESSAGE                                                      |
| > Review the README and tell me what is missing.                  |
|                                                                   |
| THINKING SUMMARY: live activity row                               |
| I need to check the README more thoroughly, especiall...          |
| [one line; the rest is clipped at this width]                     |
|                                                                   |
| ASSISTANT OUTPUT: normal answer after the turn                    |
| I found two gaps in the setup instructions.                       |
| [no completed thinking block remains in this main view]           |
+-------------------------------------------------------------------+

The full completed summary is available in the expanded transcript, outside this main view.

Previous 0.154.0 main view:

+-------------------------------------------------------------------+
| USER MESSAGE                                                      |
| > Review the README and tell me what is missing.                  |
|                                                                   |
| THINKING SUMMARY: completed block in main conversation            |
| I need to check the README more thoroughly, especially            |
| the Troubleshooting and Limitations sections, to see              |
| whether they explain the missing setup steps.                     |
|                                                                   |
| * Compare README examples with available CLI commands.            |
| * Note any known limitations.                                     |
|                                                                   |
| ASSISTANT OUTPUT: normal answer after the turn                    |
| I found two gaps in the setup instructions.                       |
+-------------------------------------------------------------------+

Possible change

An opt-in [tui] show_reasoning_summaries_in_history = true could make completed summary cells visible in both the main conversation and expanded transcript. The patch below shows one way to do that against 0.155.0. It leaves the 0.155.0 default in place. It does not change the live activity row, which would still benefit from a way to wrap or expand long text.

The intended result is simple: when the option is on, a completed multiline summary stays readable in the main conversation; when it is off, the current transcript-only behavior remains. The patch is an illustration for review, not a tested fix.

Related reports: #8204 requested incremental streaming before this change; #36499 concerns missing summaries in 0.146.0; #38073 proposes a separate split layout for conversation and activity. This request is for a choice of summary placement after the intentional 0.155.0 change.

Illustrative diff against 0.155.0
diff --git a/codex-rs/config/src/types.rs b/codex-rs/config/src/types.rs
index abd8ee0..9e69d34 100644
--- a/codex-rs/config/src/types.rs
+++ b/codex-rs/config/src/types.rs
@@ -783,6 +783,11 @@ pub struct Tui {
     #[serde(default)]
     pub raw_output_mode: bool,
 
+    /// Keep completed reasoning summaries in the main conversation as well as the transcript.
+    /// Defaults to `false`.
+    #[serde(default)]
+    pub show_reasoning_summaries_in_history: bool,
+
     /// Controls whether the TUI uses the terminal's alternate screen buffer.
     ///
     /// - `auto` (default): Use alternate screen.
diff --git a/codex-rs/core/config.schema.json b/codex-rs/core/config.schema.json
index 3507239..0765853 100644
--- a/codex-rs/core/config.schema.json
+++ b/codex-rs/core/config.schema.json
@@ -4246,6 +4246,11 @@
           "default": null,
           "description": "Preferred layout for resume/fork session picker results."
         },
+        "show_reasoning_summaries_in_history": {
+          "default": false,
+          "description": "Keep completed reasoning summaries in the main conversation as well as the transcript. Defaults to `false`.",
+          "type": "boolean"
+        },
         "show_server_version_notice": {
           "default": true,
           "description": "Show an informational notice when the connected app server is an older stable release. Defaults to `true`; this does not control compatibility errors or version status.",
@@ -7090,4 +7095,4 @@
   },
   "title": "ConfigToml",
   "type": "object"
-}
\ No newline at end of file
+}
diff --git a/codex-rs/core/src/config/config_tests.rs b/codex-rs/core/src/config/config_tests.rs
index a2be15e..ae49802 100644
--- a/codex-rs/core/src/config/config_tests.rs
+++ b/codex-rs/core/src/config/config_tests.rs
@@ -1268,6 +1268,7 @@ fn config_toml_deserializes_model_availability_nux() {
             vim_mode_default: false,
             question_esc_back: true,
             raw_output_mode: false,
+            show_reasoning_summaries_in_history: false,
             alternate_screen: AltScreenMode::default(),
             status_line: None,
             status_line_use_colors: true,
@@ -1371,6 +1372,21 @@ async fn runtime_config_uses_tui_raw_output_mode() {
     assert!(cfg.tui_raw_output_mode);
 }
 
+#[tokio::test]
+async fn runtime_config_uses_tui_reasoning_summary_history_preference() {
+    let cfg_toml: ConfigToml = toml::from_str("[tui]\nshow_reasoning_summaries_in_history = true")
+        .expect("deserialize TUI reasoning summary history preference");
+    let cfg = Config::load_from_base_config_with_overrides(
+        cfg_toml,
+        ConfigOverrides::default(),
+        tempdir().expect("tempdir").abs(),
+    )
+    .await
+    .expect("load config");
+
+    assert!(cfg.tui_show_reasoning_summaries_in_history);
+}
+
 #[tokio::test]
 async fn tui_auto_recap_defaults_and_cli_overrides() -> anyhow::Result<()> {
     for (toml, override_value, expected) in [
@@ -4284,6 +4300,7 @@ fn tui_config_missing_notifications_field_defaults_to_enabled() {
             vim_mode_default: false,
             question_esc_back: true,
             raw_output_mode: false,
+            show_reasoning_summaries_in_history: false,
             alternate_screen: AltScreenMode::Auto,
             status_line: None,
             status_line_use_colors: true,
diff --git a/codex-rs/core/src/config/mod.rs b/codex-rs/core/src/config/mod.rs
index ffbda1e..631d014 100644
--- a/codex-rs/core/src/config/mod.rs
+++ b/codex-rs/core/src/config/mod.rs
@@ -769,6 +769,9 @@ pub struct Config {
     /// Start the TUI in raw scrollback mode for copy-friendly transcript output.
     pub tui_raw_output_mode: bool,
 
+    /// Keep completed reasoning summaries in the main TUI conversation.
+    pub tui_show_reasoning_summaries_in_history: bool,
+
     /// Start the TUI in the specified collaboration mode (plan/default).
 
     /// Controls whether the TUI uses the terminal's alternate screen buffer.
@@ -4406,6 +4409,10 @@ impl Config {
                 .as_ref()
                 .map(|t| t.raw_output_mode)
                 .unwrap_or(false),
+            tui_show_reasoning_summaries_in_history: cfg
+                .tui
+                .as_ref()
+                .is_some_and(|t| t.show_reasoning_summaries_in_history),
             tui_alternate_screen: cfg
                 .tui
                 .as_ref()
diff --git a/codex-rs/tui/src/chatwidget/streaming.rs b/codex-rs/tui/src/chatwidget/streaming.rs
index 18b4216..85b8105 100644
--- a/codex-rs/tui/src/chatwidget/streaming.rs
+++ b/codex-rs/tui/src/chatwidget/streaming.rs
@@ -329,7 +329,11 @@ impl ChatWidget {
             .or(self.reasoning_header.take());
         if !self.reasoning_summary_parts.is_empty() {
             let reasoning_parts = std::mem::take(&mut self.reasoning_summary_parts);
-            let cell = history_cell::new_reasoning_summary_block(reasoning_parts, &self.config.cwd);
+            let cell = if self.local_settings.tui.show_reasoning_summaries_in_history {
+                history_cell::new_inline_reasoning_summary_block(reasoning_parts, &self.config.cwd)
+            } else {
+                history_cell::new_reasoning_summary_block(reasoning_parts, &self.config.cwd)
+            };
             self.add_boxed_history(cell);
         }
         self.reasoning_buffer.clear();
diff --git a/codex-rs/tui/src/history_cell/messages.rs b/codex-rs/tui/src/history_cell/messages.rs
index 084c4ff..851c584 100644
--- a/codex-rs/tui/src/history_cell/messages.rs
+++ b/codex-rs/tui/src/history_cell/messages.rs
@@ -676,6 +676,17 @@ pub(crate) fn new_reasoning_summary_block(
     ))
 }
 
+/// Show a completed reasoning block in both the main conversation and expanded transcript.
+pub(crate) fn new_inline_reasoning_summary_block(
+    reasoning_parts: Vec<String>,
+    cwd: &Path,
+) -> Box<dyn HistoryCell> {
+    let (header, content) = split_reasoning_summary_parts(&reasoning_parts);
+    Box::new(ReasoningSummaryCell::new(
+        header, content, cwd, /*transcript_only*/ false,
+    ))
+}
+
 /// Split structured reasoning-summary parts into the status header and renderable content.
 pub(crate) fn split_reasoning_summary_parts(reasoning_parts: &[String]) -> (String, String) {
     let mut leading_empty_part_header = None;
diff --git a/codex-rs/tui/src/history_cell/tests.rs b/codex-rs/tui/src/history_cell/tests.rs
index 138c9b5..d1f3448 100644
--- a/codex-rs/tui/src/history_cell/tests.rs
+++ b/codex-rs/tui/src/history_cell/tests.rs
@@ -2676,6 +2676,18 @@ fn reasoning_summary_block() {
     assert_eq!(rendered_transcript, vec!["• Detailed reasoning goes here."]);
 }
 
+#[test]
+fn inline_reasoning_summary_block_remains_in_main_history() {
+    let cell = new_inline_reasoning_summary_block(
+        vec!["**High level reasoning**\n\nDetailed reasoning goes here.".to_string()],
+        &test_cwd(),
+    );
+
+    let expected = vec!["• Detailed reasoning goes here."];
+    assert_eq!(render_lines(&cell.display_lines(/*width*/ 80)), expected);
+    assert_eq!(render_transcript(cell.as_ref()), expected);
+}
+
 #[test]
 fn reasoning_summary_height_matches_wrapped_rendering_for_url_like_content() {
     let summary = "example.test/api/v1/projects/alpha-team/releases/2026-02-17/builds/1234567890/artifacts/reports/performance/summary/detail/with/a/very/long/path/that/keeps/going";
diff --git a/codex-rs/tui/src/local_settings.rs b/codex-rs/tui/src/local_settings.rs
index 6a588f4..a4119e8 100644
--- a/codex-rs/tui/src/local_settings.rs
+++ b/codex-rs/tui/src/local_settings.rs
@@ -35,6 +35,7 @@ impl From<&Config> for LocalSettings {
                 vim_mode_default: config.tui_vim_mode_default,
                 question_esc_back: config.tui_question_esc_back,
                 raw_output_mode: config.tui_raw_output_mode,
+                show_reasoning_summaries_in_history: config.tui_show_reasoning_summaries_in_history,
                 alternate_screen: config.tui_alternate_screen,
                 status_line: config.tui_status_line.clone(),
                 status_line_use_colors: config.tui_status_line_use_colors,

The diff changes eight files and adds config and cell tests. git diff --check, JSON parsing of config.schema.json, and rustfmt --check on the changed Rust files passed locally. I did not compile Codex, run its TUI tests, or verify the proposed behavior in a running TUI. Those checks establish formatting and patch hygiene only.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with codex-rs/tui/src/chatwidget/streaming.rs and codex-rs/tui/src/history_cell/messages.rs, then trace the TUI setting through codex-rs/config/src/types.rs, codex-rs/core/src/config/mod.rs, and core/src/config.schema.json. Run the config tests in core/src/config/config_tests.rs, including the reasoning-summary preference test. Done means the option defaults off, enables completed summaries in the main conversation and transcript, and preserves the current behavior when unset.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
cli, developer-experience
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.