mirror of
https://github.com/openai/codex.git
synced 2026-11-06 00:30:29 +00:00
Add reasoning-only status surface item (#25504)
Closes #24886. ## Why Users can configure the TUI status line and terminal title with `model-with-reasoning`, but issue #24886 asks for a compact reasoning-only item. That lets a setup show just `default`, `low`, `medium`, `high`, or `xhigh` without repeating the model name. ## What changed - Added a `reasoning` item for `/statusline` and `/title` setup flows. - Rendered the item from the effective reasoning effort, including collaboration-mode overrides. - Registered `reasoning` with `codex doctor` so Codex-generated terminal-title config is not reported as invalid. - Updated TUI setup snapshots so the picker previews include the new item.
This commit is contained in:
1 parent
6681446477
commit
f1d029cf75
12 files changed
+83
-7
No files matched your search
@@ -143,6 +143,7 @@ fn terminal_title_item_id(item: &str) -> Option<&'static str> {
|
|||||||
"fast-mode" => Some("fast-mode"),
|
"fast-mode" => Some("fast-mode"),
|
||||||
"model" | "model-name" => Some("model"),
|
"model" | "model-name" => Some("model"),
|
||||||
"model-with-reasoning" => Some("model-with-reasoning"),
|
"model-with-reasoning" => Some("model-with-reasoning"),
|
||||||
|
"reasoning" => Some("reasoning"),
|
||||||
"task-progress" => Some("task-progress"),
|
"task-progress" => Some("task-progress"),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -14,8 +14,8 @@ expression: "render_lines(&view, 72)"
|
|||||||
[x] current-dir Current working directory
|
[x] current-dir Current working directory
|
||||||
[x] git-branch Current Git branch (omitted when unavaila…
|
[x] git-branch Current Git branch (omitted when unavaila…
|
||||||
[ ] model-with-reasoning Current model name with reasoning level
|
[ ] model-with-reasoning Current model name with reasoning level
|
||||||
|
[ ] reasoning Current reasoning level
|
||||||
[ ] project-name Project name (omitted when unavailable)
|
[ ] project-name Project name (omitted when unavailable)
|
||||||
[ ] pull-request-number Open pull request number for the current …
|
|
||||||
|
|
||||||
gpt-5-codex · ~/codex-rs · jif/statusline-preview
|
gpt-5-codex · ~/codex-rs · jif/statusline-preview
|
||||||
Press space to toggle; ←/→ to move; enter to confirm and close; esc to
|
Press space to toggle; ←/→ to move; enter to confirm and close; esc to
|
||||||
@@ -60,6 +60,9 @@ pub(crate) enum StatusLineItem {
|
|||||||
/// Model name with reasoning level suffix.
|
/// Model name with reasoning level suffix.
|
||||||
ModelWithReasoning,
|
ModelWithReasoning,
|
||||||
|
|
||||||
|
/// Current reasoning level.
|
||||||
|
Reasoning,
|
||||||
|
|
||||||
/// Current working directory path.
|
/// Current working directory path.
|
||||||
CurrentDir,
|
CurrentDir,
|
||||||
|
|
||||||
@@ -144,6 +147,7 @@ impl StatusLineItem {
|
|||||||
match self {
|
match self {
|
||||||
StatusLineItem::ModelName => "Current model name",
|
StatusLineItem::ModelName => "Current model name",
|
||||||
StatusLineItem::ModelWithReasoning => "Current model name with reasoning level",
|
StatusLineItem::ModelWithReasoning => "Current model name with reasoning level",
|
||||||
|
StatusLineItem::Reasoning => "Current reasoning level",
|
||||||
StatusLineItem::CurrentDir => "Current working directory",
|
StatusLineItem::CurrentDir => "Current working directory",
|
||||||
StatusLineItem::ProjectRoot => "Project name (omitted when unavailable)",
|
StatusLineItem::ProjectRoot => "Project name (omitted when unavailable)",
|
||||||
StatusLineItem::GitBranch => "Current Git branch (omitted when unavailable)",
|
StatusLineItem::GitBranch => "Current Git branch (omitted when unavailable)",
|
||||||
@@ -191,6 +195,7 @@ impl StatusLineItem {
|
|||||||
match self {
|
match self {
|
||||||
StatusLineItem::ModelName => StatusSurfacePreviewItem::Model,
|
StatusLineItem::ModelName => StatusSurfacePreviewItem::Model,
|
||||||
StatusLineItem::ModelWithReasoning => StatusSurfacePreviewItem::ModelWithReasoning,
|
StatusLineItem::ModelWithReasoning => StatusSurfacePreviewItem::ModelWithReasoning,
|
||||||
|
StatusLineItem::Reasoning => StatusSurfacePreviewItem::Reasoning,
|
||||||
StatusLineItem::CurrentDir => StatusSurfacePreviewItem::CurrentDir,
|
StatusLineItem::CurrentDir => StatusSurfacePreviewItem::CurrentDir,
|
||||||
StatusLineItem::ProjectRoot => StatusSurfacePreviewItem::ProjectRoot,
|
StatusLineItem::ProjectRoot => StatusSurfacePreviewItem::ProjectRoot,
|
||||||
StatusLineItem::GitBranch => StatusSurfacePreviewItem::GitBranch,
|
StatusLineItem::GitBranch => StatusSurfacePreviewItem::GitBranch,
|
||||||
@@ -450,6 +455,15 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn reasoning_is_selectable_id() {
|
||||||
|
assert_eq!(StatusLineItem::Reasoning.to_string(), "reasoning");
|
||||||
|
assert_eq!(
|
||||||
|
"reasoning".parse::<StatusLineItem>(),
|
||||||
|
Ok(StatusLineItem::Reasoning)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn run_state_is_canonical_and_accepts_status_legacy_id() {
|
fn run_state_is_canonical_and_accepts_status_legacy_id() {
|
||||||
assert_eq!(StatusLineItem::Status.to_string(), "run-state");
|
assert_eq!(StatusLineItem::Status.to_string(), "run-state");
|
||||||
|
|||||||
@@ -30,7 +30,9 @@ enum StatusLineAccent {
|
|||||||
impl StatusLineAccent {
|
impl StatusLineAccent {
|
||||||
fn for_item(item: StatusLineItem) -> Self {
|
fn for_item(item: StatusLineItem) -> Self {
|
||||||
match item {
|
match item {
|
||||||
StatusLineItem::ModelName | StatusLineItem::ModelWithReasoning => Self::Model,
|
StatusLineItem::ModelName
|
||||||
|
| StatusLineItem::ModelWithReasoning
|
||||||
|
| StatusLineItem::Reasoning => Self::Model,
|
||||||
StatusLineItem::CurrentDir | StatusLineItem::ProjectRoot => Self::Path,
|
StatusLineItem::CurrentDir | StatusLineItem::ProjectRoot => Self::Path,
|
||||||
StatusLineItem::GitBranch
|
StatusLineItem::GitBranch
|
||||||
| StatusLineItem::PullRequestNumber
|
| StatusLineItem::PullRequestNumber
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ pub(crate) enum StatusSurfacePreviewItem {
|
|||||||
RawOutput,
|
RawOutput,
|
||||||
Model,
|
Model,
|
||||||
ModelWithReasoning,
|
ModelWithReasoning,
|
||||||
|
Reasoning,
|
||||||
TaskProgress,
|
TaskProgress,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,6 +64,7 @@ impl StatusSurfacePreviewItem {
|
|||||||
StatusSurfacePreviewItem::RawOutput => "raw output",
|
StatusSurfacePreviewItem::RawOutput => "raw output",
|
||||||
StatusSurfacePreviewItem::Model => "gpt-5.2-codex",
|
StatusSurfacePreviewItem::Model => "gpt-5.2-codex",
|
||||||
StatusSurfacePreviewItem::ModelWithReasoning => "gpt-5.2-codex medium",
|
StatusSurfacePreviewItem::ModelWithReasoning => "gpt-5.2-codex medium",
|
||||||
|
StatusSurfacePreviewItem::Reasoning => "medium",
|
||||||
StatusSurfacePreviewItem::TaskProgress => "Tasks 0/0",
|
StatusSurfacePreviewItem::TaskProgress => "Tasks 0/0",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,6 +96,7 @@ impl StatusSurfacePreviewItem {
|
|||||||
Self::RawOutput,
|
Self::RawOutput,
|
||||||
Self::Model,
|
Self::Model,
|
||||||
Self::ModelWithReasoning,
|
Self::ModelWithReasoning,
|
||||||
|
Self::Reasoning,
|
||||||
Self::TaskProgress,
|
Self::TaskProgress,
|
||||||
]
|
]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|||||||
@@ -82,6 +82,8 @@ pub(crate) enum TerminalTitleItem {
|
|||||||
Model,
|
Model,
|
||||||
/// Current model name with reasoning level.
|
/// Current model name with reasoning level.
|
||||||
ModelWithReasoning,
|
ModelWithReasoning,
|
||||||
|
/// Current reasoning level.
|
||||||
|
Reasoning,
|
||||||
/// Latest checklist task progress from `update_plan` (if available).
|
/// Latest checklist task progress from `update_plan` (if available).
|
||||||
TaskProgress,
|
TaskProgress,
|
||||||
}
|
}
|
||||||
@@ -122,6 +124,7 @@ impl TerminalTitleItem {
|
|||||||
TerminalTitleItem::FastMode => "Whether Fast mode is currently active",
|
TerminalTitleItem::FastMode => "Whether Fast mode is currently active",
|
||||||
TerminalTitleItem::Model => "Current model name",
|
TerminalTitleItem::Model => "Current model name",
|
||||||
TerminalTitleItem::ModelWithReasoning => "Current model name with reasoning level",
|
TerminalTitleItem::ModelWithReasoning => "Current model name with reasoning level",
|
||||||
|
TerminalTitleItem::Reasoning => "Current reasoning level",
|
||||||
TerminalTitleItem::TaskProgress => {
|
TerminalTitleItem::TaskProgress => {
|
||||||
"Latest task progress from update_plan (omitted until available)"
|
"Latest task progress from update_plan (omitted until available)"
|
||||||
}
|
}
|
||||||
@@ -153,6 +156,7 @@ impl TerminalTitleItem {
|
|||||||
TerminalTitleItem::ModelWithReasoning => {
|
TerminalTitleItem::ModelWithReasoning => {
|
||||||
Some(StatusSurfacePreviewItem::ModelWithReasoning)
|
Some(StatusSurfacePreviewItem::ModelWithReasoning)
|
||||||
}
|
}
|
||||||
|
TerminalTitleItem::Reasoning => Some(StatusSurfacePreviewItem::Reasoning),
|
||||||
TerminalTitleItem::TaskProgress => Some(StatusSurfacePreviewItem::TaskProgress),
|
TerminalTitleItem::TaskProgress => Some(StatusSurfacePreviewItem::TaskProgress),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -516,6 +520,15 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn reasoning_is_selectable_id() {
|
||||||
|
assert_eq!(TerminalTitleItem::Reasoning.to_string(), "reasoning");
|
||||||
|
assert_eq!(
|
||||||
|
"reasoning".parse::<TerminalTitleItem>(),
|
||||||
|
Ok(TerminalTitleItem::Reasoning)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_terminal_title_items_accepts_kebab_case_variants() {
|
fn parse_terminal_title_items_accepts_kebab_case_variants() {
|
||||||
let items = parse_terminal_title_items(
|
let items = parse_terminal_title_items(
|
||||||
@@ -530,6 +543,7 @@ mod tests {
|
|||||||
"project-name",
|
"project-name",
|
||||||
"model",
|
"model",
|
||||||
"model-with-reasoning",
|
"model-with-reasoning",
|
||||||
|
"reasoning",
|
||||||
"weekly-limit",
|
"weekly-limit",
|
||||||
"codex-version",
|
"codex-version",
|
||||||
"used-tokens",
|
"used-tokens",
|
||||||
@@ -553,6 +567,7 @@ mod tests {
|
|||||||
TerminalTitleItem::Project,
|
TerminalTitleItem::Project,
|
||||||
TerminalTitleItem::Model,
|
TerminalTitleItem::Model,
|
||||||
TerminalTitleItem::ModelWithReasoning,
|
TerminalTitleItem::ModelWithReasoning,
|
||||||
|
TerminalTitleItem::Reasoning,
|
||||||
TerminalTitleItem::WeeklyLimit,
|
TerminalTitleItem::WeeklyLimit,
|
||||||
TerminalTitleItem::CodexVersion,
|
TerminalTitleItem::CodexVersion,
|
||||||
TerminalTitleItem::UsedTokens,
|
TerminalTitleItem::UsedTokens,
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@ expression: status_line_popup_snapshot(&mut chat)
|
|||||||
[x] thread-title Current thread title, or thread identifier when unnamed
|
[x] thread-title Current thread title, or thread identifier when unnamed
|
||||||
[ ] model Current model name
|
[ ] model Current model name
|
||||||
[ ] model-with-reasoning Current model name with reasoning level
|
[ ] model-with-reasoning Current model name with reasoning level
|
||||||
[ ] current-dir Current working directory
|
[ ] reasoning Current reasoning level
|
||||||
|
|
||||||
my-project · feat/awesome-feature · thread title
|
my-project · feat/awesome-feature · thread title
|
||||||
Press space to toggle; ←/→ to move; enter to confirm and close; esc to close
|
Press space to toggle; ←/→ to move; enter to confirm and close; esc to close
|
||||||
+1
-1
@@ -14,7 +14,7 @@ expression: status_line_popup_snapshot(&mut chat)
|
|||||||
[x] thread-title Current thread title, or thread identifier when unnamed
|
[x] thread-title Current thread title, or thread identifier when unnamed
|
||||||
[ ] model Current model name
|
[ ] model Current model name
|
||||||
[ ] model-with-reasoning Current model name with reasoning level
|
[ ] model-with-reasoning Current model name with reasoning level
|
||||||
[ ] current-dir Current working directory
|
[ ] reasoning Current reasoning level
|
||||||
|
|
||||||
preview-live-root · feature/live-preview-branch · Live preview thread
|
preview-live-root · feature/live-preview-branch · Live preview thread
|
||||||
Press space to toggle; ←/→ to move; enter to confirm and close; esc to close
|
Press space to toggle; ←/→ to move; enter to confirm and close; esc to close
|
||||||
+1
-1
@@ -14,7 +14,7 @@ expression: status_line_popup_snapshot(&mut chat)
|
|||||||
[x] thread-title Current thread title, or thread identifier when unnamed
|
[x] thread-title Current thread title, or thread identifier when unnamed
|
||||||
[ ] model Current model name
|
[ ] model Current model name
|
||||||
[ ] model-with-reasoning Current model name with reasoning level
|
[ ] model-with-reasoning Current model name with reasoning level
|
||||||
[ ] current-dir Current working directory
|
[ ] reasoning Current reasoning level
|
||||||
|
|
||||||
my-project · feature/mixed-preview · Mixed preview thread
|
my-project · feature/mixed-preview · Mixed preview thread
|
||||||
Press space to toggle; ←/→ to move; enter to confirm and close; esc to close
|
Press space to toggle; ←/→ to move; enter to confirm and close; esc to close
|
||||||
+1
-1
@@ -13,8 +13,8 @@ expression: status_line_popup_snapshot(&mut chat)
|
|||||||
[x] weekly-limit Remaining usage on the weekly usage limit (omitted when unavailable)
|
[x] weekly-limit Remaining usage on the weekly usage limit (omitted when unavailable)
|
||||||
[ ] model Current model name
|
[ ] model Current model name
|
||||||
[ ] model-with-reasoning Current model name with reasoning level
|
[ ] model-with-reasoning Current model name with reasoning level
|
||||||
|
[ ] reasoning Current reasoning level
|
||||||
[ ] current-dir Current working directory
|
[ ] current-dir Current working directory
|
||||||
[ ] project-name Project name (omitted when unavailable)
|
|
||||||
|
|
||||||
monthly 65% left · weekly 50% left
|
monthly 65% left · weekly 50% left
|
||||||
Press space to toggle; ←/→ to move; enter to confirm and close; esc to close
|
Press space to toggle; ←/→ to move; enter to confirm and close; esc to close
|
||||||
@@ -562,6 +562,7 @@ impl ChatWidget {
|
|||||||
match item {
|
match item {
|
||||||
StatusLineItem::ModelName => Some(self.model_display_name().to_string()),
|
StatusLineItem::ModelName => Some(self.model_display_name().to_string()),
|
||||||
StatusLineItem::ModelWithReasoning => Some(self.model_with_reasoning_display_name()),
|
StatusLineItem::ModelWithReasoning => Some(self.model_with_reasoning_display_name()),
|
||||||
|
StatusLineItem::Reasoning => Some(self.reasoning_display_name().to_string()),
|
||||||
StatusLineItem::CurrentDir => {
|
StatusLineItem::CurrentDir => {
|
||||||
Some(format_directory_display(
|
Some(format_directory_display(
|
||||||
self.status_line_cwd(),
|
self.status_line_cwd(),
|
||||||
@@ -694,6 +695,7 @@ impl ChatWidget {
|
|||||||
StatusSurfacePreviewItem::RawOutput => StatusLineItem::RawOutput,
|
StatusSurfacePreviewItem::RawOutput => StatusLineItem::RawOutput,
|
||||||
StatusSurfacePreviewItem::Model => StatusLineItem::ModelName,
|
StatusSurfacePreviewItem::Model => StatusLineItem::ModelName,
|
||||||
StatusSurfacePreviewItem::ModelWithReasoning => StatusLineItem::ModelWithReasoning,
|
StatusSurfacePreviewItem::ModelWithReasoning => StatusLineItem::ModelWithReasoning,
|
||||||
|
StatusSurfacePreviewItem::Reasoning => StatusLineItem::Reasoning,
|
||||||
};
|
};
|
||||||
self.status_line_value_for_item(status_line_item)
|
self.status_line_value_for_item(status_line_item)
|
||||||
}
|
}
|
||||||
@@ -759,12 +761,20 @@ impl ChatWidget {
|
|||||||
self.model_with_reasoning_display_name(),
|
self.model_with_reasoning_display_name(),
|
||||||
/*max_chars*/ 32,
|
/*max_chars*/ 32,
|
||||||
)),
|
)),
|
||||||
|
TerminalTitleItem::Reasoning => Some(Self::truncate_terminal_title_part(
|
||||||
|
self.reasoning_display_name().to_string(),
|
||||||
|
/*max_chars*/ 32,
|
||||||
|
)),
|
||||||
TerminalTitleItem::TaskProgress => self.terminal_title_task_progress(),
|
TerminalTitleItem::TaskProgress => self.terminal_title_task_progress(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reasoning_display_name(&self) -> &'static str {
|
||||||
|
Self::status_line_reasoning_effort_label(self.effective_reasoning_effort())
|
||||||
|
}
|
||||||
|
|
||||||
fn model_with_reasoning_display_name(&self) -> String {
|
fn model_with_reasoning_display_name(&self) -> String {
|
||||||
let label = Self::status_line_reasoning_effort_label(self.effective_reasoning_effort());
|
let label = self.reasoning_display_name();
|
||||||
let service_tier_label = self
|
let service_tier_label = self
|
||||||
.current_service_tier()
|
.current_service_tier()
|
||||||
.and_then(|service_tier| {
|
.and_then(|service_tier| {
|
||||||
|
|||||||
@@ -2208,6 +2208,37 @@ async fn terminal_title_model_updates_on_model_change_without_manual_refresh() {
|
|||||||
assert_eq!(chat.last_terminal_title, Some("gpt-5.3-codex".to_string()));
|
assert_eq!(chat.last_terminal_title, Some("gpt-5.3-codex".to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn status_line_and_terminal_title_reasoning_render_only_effort() {
|
||||||
|
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.4")).await;
|
||||||
|
chat.config.tui_status_line = Some(vec!["reasoning".to_string()]);
|
||||||
|
chat.config.tui_terminal_title = Some(vec!["reasoning".to_string()]);
|
||||||
|
chat.set_reasoning_effort(Some(ReasoningEffortConfig::XHigh));
|
||||||
|
chat.set_service_tier(Some(ServiceTier::Fast.request_value().to_string()));
|
||||||
|
|
||||||
|
chat.refresh_status_line();
|
||||||
|
chat.refresh_terminal_title();
|
||||||
|
|
||||||
|
assert_eq!(status_line_text(&chat), Some("xhigh".to_string()));
|
||||||
|
assert_eq!(chat.last_terminal_title, Some("xhigh".to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn status_line_reasoning_updates_on_mode_switch_without_manual_refresh() {
|
||||||
|
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.3-codex")).await;
|
||||||
|
chat.set_feature_enabled(Feature::CollaborationModes, /*enabled*/ true);
|
||||||
|
chat.config.tui_status_line = Some(vec!["reasoning".to_string()]);
|
||||||
|
chat.set_reasoning_effort(Some(ReasoningEffortConfig::High));
|
||||||
|
|
||||||
|
assert_eq!(status_line_text(&chat), Some("high".to_string()));
|
||||||
|
|
||||||
|
let plan_mask = collaboration_modes::plan_mask(chat.model_catalog.as_ref())
|
||||||
|
.expect("expected plan collaboration mode");
|
||||||
|
chat.set_collaboration_mask(plan_mask);
|
||||||
|
|
||||||
|
assert_eq!(status_line_text(&chat), Some("medium".to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn status_line_model_with_reasoning_updates_on_mode_switch_without_manual_refresh() {
|
async fn status_line_model_with_reasoning_updates_on_mode_switch_without_manual_refresh() {
|
||||||
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.3-codex")).await;
|
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.3-codex")).await;
|
||||||
|
|||||||
Reference in new issue
Block a user