Parse reasoning text content (#2277)
Sometimes COT is returns as text content instead of `ReasoningText`. We should parse it but not serialize back on requests. --------- Co-authored-by: Ahmed Ibrahim <aibrahim@openai.com>
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
---
|
||||
source: tui/src/chatwidget/tests.rs
|
||||
assertion_line: 886
|
||||
expression: combined
|
||||
---
|
||||
thinking
|
||||
I will first analyze the request.
|
||||
|
||||
codex
|
||||
Here is the result.
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
source: tui/src/chatwidget/tests.rs
|
||||
expression: combined
|
||||
---
|
||||
thinking
|
||||
I will first analyze the request.
|
||||
|
||||
codex
|
||||
Here is the result.
|
||||
@@ -12,6 +12,7 @@ use codex_core::plan_tool::UpdatePlanArgs;
|
||||
use codex_core::protocol::AgentMessageDeltaEvent;
|
||||
use codex_core::protocol::AgentMessageEvent;
|
||||
use codex_core::protocol::AgentReasoningDeltaEvent;
|
||||
use codex_core::protocol::AgentReasoningEvent;
|
||||
use codex_core::protocol::ApplyPatchApprovalRequestEvent;
|
||||
use codex_core::protocol::Event;
|
||||
use codex_core::protocol::EventMsg;
|
||||
@@ -24,6 +25,7 @@ use codex_core::protocol::TaskCompleteEvent;
|
||||
use crossterm::event::KeyCode;
|
||||
use crossterm::event::KeyEvent;
|
||||
use crossterm::event::KeyModifiers;
|
||||
use insta::assert_snapshot;
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::fs::File;
|
||||
use std::io::BufRead;
|
||||
@@ -413,46 +415,6 @@ async fn binary_size_transcript_matches_ideal_fixture() {
|
||||
assert_eq!(visible_after, ideal);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn final_longer_answer_after_single_char_delta_is_complete() {
|
||||
let (mut chat, rx, _op_rx) = make_chatwidget_manual();
|
||||
|
||||
// Simulate a stray delta without newline (e.g., punctuation).
|
||||
chat.handle_codex_event(Event {
|
||||
id: "sub-x".into(),
|
||||
msg: EventMsg::AgentMessageDelta(AgentMessageDeltaEvent { delta: "?".into() }),
|
||||
});
|
||||
|
||||
// Now send the full final answer with no newline.
|
||||
let full = "Hi! How can I help with codex-rs today? Want me to explore the repo, run tests, or work on a specific change?";
|
||||
chat.handle_codex_event(Event {
|
||||
id: "sub-x".into(),
|
||||
msg: EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: full.into(),
|
||||
}),
|
||||
});
|
||||
|
||||
// Drain and assert the full message appears in history.
|
||||
let cells = drain_insert_history(&rx);
|
||||
let mut found = false;
|
||||
for lines in &cells {
|
||||
let s = lines
|
||||
.iter()
|
||||
.flat_map(|l| l.spans.iter())
|
||||
.map(|sp| sp.content.clone())
|
||||
.collect::<String>();
|
||||
if s.contains(full) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert!(
|
||||
found,
|
||||
"expected full final message to be flushed to history, cells={:?}",
|
||||
cells.len()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_patch_events_emit_history_cells() {
|
||||
let (mut chat, rx, _op_rx) = make_chatwidget_manual();
|
||||
@@ -923,3 +885,91 @@ fn multiple_agent_messages_in_single_turn_emit_multiple_headers() {
|
||||
let second_idx = combined.find("Second message").unwrap();
|
||||
assert!(first_idx < second_idx, "messages out of order: {combined}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn final_reasoning_then_message_without_deltas_are_rendered() {
|
||||
let (mut chat, rx, _op_rx) = make_chatwidget_manual();
|
||||
|
||||
// No deltas; only final reasoning followed by final message.
|
||||
chat.handle_codex_event(Event {
|
||||
id: "s1".into(),
|
||||
msg: EventMsg::AgentReasoning(AgentReasoningEvent {
|
||||
text: "I will first analyze the request.".into(),
|
||||
}),
|
||||
});
|
||||
chat.handle_codex_event(Event {
|
||||
id: "s1".into(),
|
||||
msg: EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "Here is the result.".into(),
|
||||
}),
|
||||
});
|
||||
|
||||
// Drain history and snapshot the combined visible content.
|
||||
let cells = drain_insert_history(&rx);
|
||||
let combined = cells
|
||||
.iter()
|
||||
.map(|lines| lines_to_single_string(lines))
|
||||
.collect::<String>();
|
||||
assert_snapshot!(combined);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deltas_then_same_final_message_are_rendered_snapshot() {
|
||||
let (mut chat, rx, _op_rx) = make_chatwidget_manual();
|
||||
|
||||
// Stream some reasoning deltas first.
|
||||
chat.handle_codex_event(Event {
|
||||
id: "s1".into(),
|
||||
msg: EventMsg::AgentReasoningDelta(AgentReasoningDeltaEvent {
|
||||
delta: "I will ".into(),
|
||||
}),
|
||||
});
|
||||
chat.handle_codex_event(Event {
|
||||
id: "s1".into(),
|
||||
msg: EventMsg::AgentReasoningDelta(AgentReasoningDeltaEvent {
|
||||
delta: "first analyze the ".into(),
|
||||
}),
|
||||
});
|
||||
chat.handle_codex_event(Event {
|
||||
id: "s1".into(),
|
||||
msg: EventMsg::AgentReasoningDelta(AgentReasoningDeltaEvent {
|
||||
delta: "request.".into(),
|
||||
}),
|
||||
});
|
||||
chat.handle_codex_event(Event {
|
||||
id: "s1".into(),
|
||||
msg: EventMsg::AgentReasoning(AgentReasoningEvent {
|
||||
text: "request.".into(),
|
||||
}),
|
||||
});
|
||||
|
||||
// Then stream answer deltas, followed by the exact same final message.
|
||||
chat.handle_codex_event(Event {
|
||||
id: "s1".into(),
|
||||
msg: EventMsg::AgentMessageDelta(AgentMessageDeltaEvent {
|
||||
delta: "Here is the ".into(),
|
||||
}),
|
||||
});
|
||||
chat.handle_codex_event(Event {
|
||||
id: "s1".into(),
|
||||
msg: EventMsg::AgentMessageDelta(AgentMessageDeltaEvent {
|
||||
delta: "result.".into(),
|
||||
}),
|
||||
});
|
||||
|
||||
chat.handle_codex_event(Event {
|
||||
id: "s1".into(),
|
||||
msg: EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "Here is the result.".into(),
|
||||
}),
|
||||
});
|
||||
|
||||
// Snapshot the combined visible content to ensure we render as expected
|
||||
// when deltas are followed by the identical final message.
|
||||
let cells = drain_insert_history(&rx);
|
||||
let combined = cells
|
||||
.iter()
|
||||
.map(|lines| lines_to_single_string(lines))
|
||||
.collect::<String>();
|
||||
assert_snapshot!(combined);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user