mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
fix(tui): avoid duplicate live reasoning summaries (#15758)
## TL;DR Fix duplicated reasoning summaries in `tui_app_server`. <img width="1716" height="912" alt="image" src="https://github.com/user-attachments/assets/6362f25a-ab1c-4a01-bf10-b5616c9428c2" /> During live turns, reasoning text is already rendered incrementally from `ReasoningSummaryTextDelta`. When the same reasoning item later arrives via `ItemCompleted`, we should only finalize the reasoning block, not render the same summary again. ## What changed - only replay rendered reasoning summaries from completed `ThreadItem::Reasoning` items - kept live completed reasoning items as finalize-only - added a regression test covering the live streaming + completion path ## Why Without this, the first reasoning summary often appears twice in the transcript when `model_reasoning_summary = "detailed"` and `features.tui_app_server = true`.
This commit is contained in:
committed by
GitHub
Unverified
parent
f190a95a4f
commit
c6ffe9abab
@@ -5675,13 +5675,15 @@ impl ChatWidget {
|
||||
ThreadItem::Reasoning {
|
||||
summary, content, ..
|
||||
} => {
|
||||
for delta in summary {
|
||||
self.on_agent_reasoning_delta(delta);
|
||||
}
|
||||
if self.config.show_raw_agent_reasoning {
|
||||
for delta in content {
|
||||
if from_replay {
|
||||
for delta in summary {
|
||||
self.on_agent_reasoning_delta(delta);
|
||||
}
|
||||
if self.config.show_raw_agent_reasoning {
|
||||
for delta in content {
|
||||
self.on_agent_reasoning_delta(delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.on_agent_reasoning_final();
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ use codex_app_server_protocol::PluginMarketplaceEntry;
|
||||
use codex_app_server_protocol::PluginReadResponse;
|
||||
use codex_app_server_protocol::PluginSource;
|
||||
use codex_app_server_protocol::PluginSummary;
|
||||
use codex_app_server_protocol::ReasoningSummaryTextDeltaNotification;
|
||||
use codex_app_server_protocol::ServerNotification;
|
||||
use codex_app_server_protocol::SkillSummary;
|
||||
use codex_app_server_protocol::ThreadClosedNotification;
|
||||
@@ -5135,6 +5136,56 @@ async fn replayed_reasoning_item_shows_raw_reasoning_when_enabled() {
|
||||
assert!(rendered.contains("Raw reasoning"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn live_reasoning_summary_is_not_rendered_twice_when_item_completes() {
|
||||
let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(None).await;
|
||||
chat.show_welcome_banner = false;
|
||||
|
||||
chat.handle_server_notification(
|
||||
ServerNotification::TurnStarted(TurnStartedNotification {
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn: AppServerTurn {
|
||||
id: "turn-1".to_string(),
|
||||
items: Vec::new(),
|
||||
status: AppServerTurnStatus::InProgress,
|
||||
error: None,
|
||||
},
|
||||
}),
|
||||
None,
|
||||
);
|
||||
let _ = drain_insert_history(&mut rx);
|
||||
|
||||
chat.handle_server_notification(
|
||||
ServerNotification::ReasoningSummaryTextDelta(ReasoningSummaryTextDeltaNotification {
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
item_id: "reasoning-1".to_string(),
|
||||
delta: "Summary only".to_string(),
|
||||
summary_index: 0,
|
||||
}),
|
||||
None,
|
||||
);
|
||||
|
||||
chat.handle_server_notification(
|
||||
ServerNotification::ItemCompleted(ItemCompletedNotification {
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
item: AppServerThreadItem::Reasoning {
|
||||
id: "reasoning-1".to_string(),
|
||||
summary: vec!["Summary only".to_string()],
|
||||
content: Vec::new(),
|
||||
},
|
||||
}),
|
||||
None,
|
||||
);
|
||||
|
||||
let rendered = match rx.try_recv() {
|
||||
Ok(AppEvent::InsertHistoryCell(cell)) => lines_to_single_string(&cell.transcript_lines(80)),
|
||||
other => panic!("expected InsertHistoryCell, got {other:?}"),
|
||||
};
|
||||
assert_eq!(rendered.matches("Summary only").count(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rendered_user_message_event_from_inputs_matches_flattened_user_message_shape() {
|
||||
let local_image = PathBuf::from("/tmp/local.png");
|
||||
|
||||
Reference in New Issue
Block a user