mirror of
https://github.com/openai/codex.git
synced 2026-04-28 18:32:04 +03:00
6.3 KiB
6.3 KiB
DOs
- Boldly handle both streaming and non‑streaming paths: print headers on first delta, flush each chunk, and still render the final non‑delta message/reasoning if no deltas arrived.
match event {
EventMsg::AgentMessageDelta(AgentMessageDeltaEvent { delta }) => {
if !self.answer_started {
ts_println!(self, "{}\n", "codex".style(self.italic).style(self.magenta));
self.answer_started = true;
}
print!("{delta}");
#[allow(clippy::expect_used)]
std::io::stdout().flush().expect("could not flush stdout");
}
EventMsg::AgentMessage(AgentMessageEvent { message }) => {
if !self.answer_started {
ts_println!(self, "{}\n{}", "codex".style(self.italic).style(self.magenta), message);
} else {
println!();
self.answer_started = false;
}
}
_ => {}
}
- Stream “thinking” only when enabled and use the correct label; mirror the answer flow for reasoning.
EventMsg::AgentReasoningDelta(AgentReasoningDeltaEvent { delta }) => {
if self.show_agent_reasoning {
if !self.reasoning_started {
ts_println!(self, "{}\n", "thinking".style(self.italic).style(self.magenta));
self.reasoning_started = true;
}
print!("{delta}");
#[allow(clippy::expect_used)]
std::io::stdout().flush().expect("could not flush stdout");
}
}
EventMsg::AgentReasoning(AgentReasoningEvent { text }) => {
if self.show_agent_reasoning {
if !self.reasoning_started {
ts_println!(self, "{}\n{}", "thinking".style(self.italic).style(self.magenta), text);
} else {
println!();
self.reasoning_started = false;
}
}
}
- Flush stdout on every streamed chunk to keep the CLI/TUI responsive.
print!("{delta}");
#[allow(clippy::expect_used)]
std::io::stdout().flush().expect("could not flush stdout");
- Prefer if/else over early returns inside large match arms to keep control flow easy to reason about.
if !self.answer_started {
ts_println!(self, "{}\n{}", "codex".style(self.italic).style(self.magenta), message);
} else {
println!();
self.answer_started = false;
}
- Keep
usestatements at the top (or fully qualify) instead of sprinkling imports inside match arms.
// Top of file:
use std::io::Write;
// or fully qualify where used:
std::io::stdout().flush().expect("could not flush stdout");
- Inline variables directly in formatting macros.
println!("tokens used: {total_tokens}");
ts_println!(self, "command: {cmd}");
- Implement streaming in the TUI with buffers and “replace last” semantics.
// Agent message streaming
EventMsg::AgentMessageDelta(AgentMessageDeltaEvent { delta }) => {
if self.answer_buffer.is_empty() {
self.conversation_history.add_agent_message(&self.config, "".to_string());
}
self.answer_buffer.push_str(&delta);
self.conversation_history.replace_prev_agent_message(&self.config, self.answer_buffer.clone());
self.request_redraw();
}
EventMsg::AgentMessage(AgentMessageEvent { message }) => {
if self.answer_buffer.is_empty() {
self.conversation_history.add_agent_message(&self.config, message);
} else {
self.conversation_history.replace_prev_agent_message(&self.config, message);
self.answer_buffer.clear();
}
self.request_redraw();
}
- When replacing the last rendered cell, recompute height and set
0if width is unknown.
let width = self.cached_width.get();
let height = if width > 0 { entry.cell.height(width) } else { 0 };
entry.line_count.set(height);
- Place throttling/debounce at the top-level TUI event loop (not inside widgets), and never throttle user-typed input redraws.
// Event loop sketch
match app_event {
AppEvent::Key(_) => {
needs_immediate_redraw = true;
draw_now();
}
AppEvent::Redraw => {
if needs_immediate_redraw || last_draw.elapsed() >= Duration::from_millis(16) {
draw_now();
needs_immediate_redraw = false;
} else {
schedule_coalesced_redraw();
}
}
_ => {}
}
-
Keep code/comments concise and accurate; remove redundant doc comments on obvious fields like
answer_startedandreasoning_started. -
Finish streamed answers cleanly: print a newline and reset flags to prepare for the next message.
println!();
self.answer_started = false;
- Maintain small style fixes that improve clarity (e.g., ASCII apostrophes in user-facing text, no stray trailing commas in macro calls).
ts_println!(self, "{}\n", "codex".style(self.italic).style(self.magenta));
DON’Ts
- Don’t rely solely on deltas; non‑streaming responses must still render final messages/reasoning.
// Missing final AgentMessage handler means non-streaming prints nothing — avoid this.
- Don’t use early
returninside match arms when a simple if/else suffices.
// Avoid
if !self.answer_started {
ts_println!(self, "{}\n{}", "codex".style(self.italic).style(self.magenta), message);
return;
}
println!();
- Don’t
use std::io::Write;inside a match arm or branch.
// Avoid
use std::io::Write; // nested inside logic
- Don’t throttle redraws in widgets like
ChatWidget; doing so can drop visible updates and feel laggy.
// Avoid throttling here:
fn request_redraw(&mut self) {
if Instant::now().duration_since(self.last_redraw_time) > Duration::from_millis(100) {
self.app_event_tx.send(AppEvent::Redraw);
}
}
- Don’t leave misleading or redundant comments (e.g., “else, we rerender one last time” when there’s no exclusive else).
// Avoid comments that restate code or mislead the reader.
- Don’t use the wrong label for reasoning vs. answers (“thinking” vs. “codex”).
// Avoid
ts_println!(self, "{}\n", "codex".style(self.italic).style(self.magenta)); // for reasoning
- Don’t forget to guard reasoning output behind
show_agent_reasoning.
// Avoid
print!("{delta}"); // without checking self.show_agent_reasoning
- Don’t ignore zero width when recomputing layout; not setting
line_countcan break scrolling and rendering.
// Avoid
entry.line_count.set(entry.cell.height(width)); // width may be 0