diff --git a/codex-rs/core/src/config.rs b/codex-rs/core/src/config.rs index 8d66772b..2b8d7d92 100644 --- a/codex-rs/core/src/config.rs +++ b/codex-rs/core/src/config.rs @@ -1,6 +1,7 @@ use crate::config_profile::ConfigProfile; use crate::config_types::History; use crate::config_types::McpServerConfig; +use crate::config_types::ReasoningSummaryFormat; use crate::config_types::SandboxWorkspaceWrite; use crate::config_types::ShellEnvironmentPolicy; use crate::config_types::ShellEnvironmentPolicyToml; @@ -185,8 +186,6 @@ pub struct Config { /// All characters are inserted as they are received, and no buffering /// or placeholder replacement will occur for fast keypress bursts. pub disable_paste_burst: bool, - - pub use_experimental_reasoning_summary: bool, } impl Config { @@ -473,6 +472,9 @@ pub struct ConfigToml { /// Override to force-enable reasoning summaries for the configured model. pub model_supports_reasoning_summaries: Option, + /// Override to force reasoning summary format for the configured model. + pub model_reasoning_summary_format: Option, + /// Base URL for requests to ChatGPT (as opposed to the OpenAI API). pub chatgpt_base_url: Option, @@ -484,8 +486,6 @@ pub struct ConfigToml { pub experimental_use_exec_command_tool: Option, - pub use_experimental_reasoning_summary: Option, - /// The value for the `originator` header included with Responses API requests. pub responses_originator_header_internal_override: Option, @@ -713,11 +713,15 @@ impl Config { let model_family = find_family_for_model(&model).unwrap_or_else(|| { let supports_reasoning_summaries = cfg.model_supports_reasoning_summaries.unwrap_or(false); + let reasoning_summary_format = cfg + .model_reasoning_summary_format + .unwrap_or(ReasoningSummaryFormat::None); ModelFamily { slug: model.clone(), family: model.clone(), needs_special_apply_patch_instructions: false, supports_reasoning_summaries, + reasoning_summary_format, uses_local_shell_tool: false, apply_patch_tool_type: None, } @@ -811,9 +815,6 @@ impl Config { .unwrap_or(false), include_view_image_tool, disable_paste_burst: cfg.disable_paste_burst.unwrap_or(false), - use_experimental_reasoning_summary: cfg - .use_experimental_reasoning_summary - .unwrap_or(false), }; Ok(config) } @@ -1192,7 +1193,6 @@ model_verbosity = "high" use_experimental_streamable_shell_tool: false, include_view_image_tool: true, disable_paste_burst: false, - use_experimental_reasoning_summary: false, }, o3_profile_config ); @@ -1251,7 +1251,6 @@ model_verbosity = "high" use_experimental_streamable_shell_tool: false, include_view_image_tool: true, disable_paste_burst: false, - use_experimental_reasoning_summary: false, }; assert_eq!(expected_gpt3_profile_config, gpt3_profile_config); @@ -1325,7 +1324,6 @@ model_verbosity = "high" use_experimental_streamable_shell_tool: false, include_view_image_tool: true, disable_paste_burst: false, - use_experimental_reasoning_summary: false, }; assert_eq!(expected_zdr_profile_config, zdr_profile_config); @@ -1385,7 +1383,6 @@ model_verbosity = "high" use_experimental_streamable_shell_tool: false, include_view_image_tool: true, disable_paste_burst: false, - use_experimental_reasoning_summary: false, }; assert_eq!(expected_gpt5_profile_config, gpt5_profile_config); diff --git a/codex-rs/core/src/config_types.rs b/codex-rs/core/src/config_types.rs index d6661699..7335fa7e 100644 --- a/codex-rs/core/src/config_types.rs +++ b/codex-rs/core/src/config_types.rs @@ -183,3 +183,11 @@ impl From for ShellEnvironmentPolicy { } } } + +#[derive(Deserialize, Debug, Clone, PartialEq, Eq, Default, Hash)] +#[serde(rename_all = "kebab-case")] +pub enum ReasoningSummaryFormat { + #[default] + None, + Experimental, +} diff --git a/codex-rs/core/src/model_family.rs b/codex-rs/core/src/model_family.rs index 6aff0d09..5b4ca39e 100644 --- a/codex-rs/core/src/model_family.rs +++ b/codex-rs/core/src/model_family.rs @@ -1,3 +1,4 @@ +use crate::config_types::ReasoningSummaryFormat; use crate::tool_apply_patch::ApplyPatchToolType; /// A model family is a group of models that share certain characteristics. @@ -20,6 +21,9 @@ pub struct ModelFamily { // `summary` is optional). pub supports_reasoning_summaries: bool, + // Define if we need a special handling of reasoning summary + pub reasoning_summary_format: ReasoningSummaryFormat, + // This should be set to true when the model expects a tool named // "local_shell" to be provided. Its contract must be understood natively by // the model such that its description can be omitted. @@ -41,6 +45,7 @@ macro_rules! model_family { family: $family.to_string(), needs_special_apply_patch_instructions: false, supports_reasoning_summaries: false, + reasoning_summary_format: ReasoningSummaryFormat::None, uses_local_shell_tool: false, apply_patch_tool_type: None, }; @@ -61,6 +66,7 @@ macro_rules! simple_model_family { family: $family.to_string(), needs_special_apply_patch_instructions: false, supports_reasoning_summaries: false, + reasoning_summary_format: ReasoningSummaryFormat::None, uses_local_shell_tool: false, apply_patch_tool_type: None, }) @@ -90,6 +96,7 @@ pub fn find_family_for_model(slug: &str) -> Option { model_family!( slug, slug, supports_reasoning_summaries: true, + reasoning_summary_format: ReasoningSummaryFormat::Experimental, ) } else if slug.starts_with("gpt-4.1") { model_family!( diff --git a/codex-rs/tui/src/history_cell.rs b/codex-rs/tui/src/history_cell.rs index 72adb196..798a87dc 100644 --- a/codex-rs/tui/src/history_cell.rs +++ b/codex-rs/tui/src/history_cell.rs @@ -11,6 +11,7 @@ use codex_common::elapsed::format_duration; use codex_core::auth::get_auth_file; use codex_core::auth::try_read_auth_json; use codex_core::config::Config; +use codex_core::config_types::ReasoningSummaryFormat; use codex_core::plan_tool::PlanItemArg; use codex_core::plan_tool::StepStatus; use codex_core::plan_tool::UpdatePlanArgs; @@ -1244,7 +1245,7 @@ pub(crate) fn new_reasoning_summary_block( full_reasoning_buffer: String, config: &Config, ) -> Vec> { - if config.use_experimental_reasoning_summary { + if config.model_family.reasoning_summary_format == ReasoningSummaryFormat::Experimental { // Experimental format is following: // ** header ** // @@ -1856,7 +1857,7 @@ mod tests { #[test] fn reasoning_summary_block_returns_reasoning_cell_when_feature_disabled() { let mut config = test_config(); - config.use_experimental_reasoning_summary = false; + config.model_family.reasoning_summary_format = ReasoningSummaryFormat::Experimental; let cells = new_reasoning_summary_block("Detailed reasoning goes here.".to_string(), &config); @@ -1869,7 +1870,7 @@ mod tests { #[test] fn reasoning_summary_block_falls_back_when_header_is_missing() { let mut config = test_config(); - config.use_experimental_reasoning_summary = true; + config.model_family.reasoning_summary_format = ReasoningSummaryFormat::Experimental; let cells = new_reasoning_summary_block( "**High level reasoning without closing".to_string(), @@ -1887,7 +1888,7 @@ mod tests { #[test] fn reasoning_summary_block_falls_back_when_summary_is_missing() { let mut config = test_config(); - config.use_experimental_reasoning_summary = true; + config.model_family.reasoning_summary_format = ReasoningSummaryFormat::Experimental; let cells = new_reasoning_summary_block( "**High level reasoning without closing**".to_string(), @@ -1917,7 +1918,7 @@ mod tests { #[test] fn reasoning_summary_block_splits_header_and_summary_when_present() { let mut config = test_config(); - config.use_experimental_reasoning_summary = true; + config.model_family.reasoning_summary_format = ReasoningSummaryFormat::Experimental; let cells = new_reasoning_summary_block( "**High level plan**\n\nWe should fix the bug next.".to_string(), diff --git a/docs/config.md b/docs/config.md index 5d7573fe..285c2ef8 100644 --- a/docs/config.md +++ b/docs/config.md @@ -607,11 +607,11 @@ Options that are specific to the TUI. | `model_reasoning_summary` | `auto` \| `concise` \| `detailed` \| `none` | Reasoning summaries. | | `model_verbosity` | `low` \| `medium` \| `high` | GPT‑5 text verbosity (Responses API). | | `model_supports_reasoning_summaries` | boolean | Force‑enable reasoning summaries. | +| `model_reasoning_summary_format` | `none` \| `experimental` | Force reasoning summary format. | | `chatgpt_base_url` | string | Base URL for ChatGPT auth flow. | | `experimental_resume` | string (path) | Resume JSONL path (internal/experimental). | | `experimental_instructions_file` | string (path) | Replace built‑in instructions (experimental). | | `experimental_use_exec_command_tool` | boolean | Use experimental exec command tool. | -| `use_experimental_reasoning_summary` | boolean | Use experimental summary for reasoning chain. | | `responses_originator_header_internal_override` | string | Override `originator` header value. | | `projects..trust_level` | string | Mark project/worktree as trusted (only `"trusted"` is recognized). | | `preferred_auth_method` | `chatgpt` \| `apikey` | Select default auth method (default: `chatgpt`). |