Files
codex/prs/bolinfest/study/PR-1529-study.md
2025-09-02 15:17:45 -07:00

4.8 KiB
Raw Blame History

DOs

  • Use format! with raw strings and inline variables into {}.
let prompt = format!(
    r#"This chat continues a previous conversation.
After providing the summary, acknowledge that /compact was applied.

Here is the summary:

{}"#,
    summary.trim()
);
  • Keep “important first”: define App and primary fns before helpers.
impl App<'_> {
    fn dispatch_codex_event(&mut self, event: Event) {
        if let Some(p) = &mut self.pending_summarization {
            self.handle_summarization_response(event, p);
            return;
        }
        if let AppState::Chat { widget } = &mut self.app_state {
            widget.handle_codex_event(event);
        }
    }
}

// Helper lives after the caller.
fn handle_summarization_response(&mut self, event: Event, pending: &mut PendingSummarization) { /* ... */ }
  • Bring long paths into scope with use for readability.
use codex_core::protocol::EventMsg;

match &event.msg {
    EventMsg::AgentMessage(msg) => { /* ... */ }
    EventMsg::TaskComplete(done) => { /* ... */ }
    _ => {}
}
  • Keep event-loop slim; route logic to helpers like dispatch_codex_event().
match app_event {
    AppEvent::CodexEvent(e) => self.dispatch_codex_event(e),
    AppEvent::RequestRedraw => self.pending_redraw = true,
    _ => {}
}
  • Gate summarization collection to the specific summarize task, not all messages.
// When submitting the op, record the task id.
let task_id = widget.submit_op(Op::SummarizeContext);
self.pending_summarization = Some(PendingSummarization {
    task_id,
    started_receiving: false,
    buffer: String::new(),
});

// Later, only collect messages for that task.
if let (Some(p), EventMsg::AgentMessage(msg)) = (&mut self.pending_summarization, &event.msg) {
    if event.task_id == Some(p.task_id) {
        p.started_receiving = true;
        p.buffer.push_str(&msg.message);
        p.buffer.push('\n');
    }
}
  • Match enum and UI ordering by frequency; place /compact right after /new and mirror in descriptions.
#[derive(EnumIter, Clone, Copy)]
pub enum SlashCommand {
    New,
    Compact,
    Diff,
    Quit,
    ToggleMouseMode,
}

impl SlashCommand {
    pub fn description(self) -> &'static str {
        match self {
            SlashCommand::New => "Start a new chat.",
            SlashCommand::Compact => "Summarize and compact the current conversation to free up context.",
            SlashCommand::Diff => "Show git diff of the working directory (including untracked files)",
            SlashCommand::Quit => "Exit the application.",
            SlashCommand::ToggleMouseMode => "Toggle mouse mode (enable for scrolling, disable for text selection)",
        }
    }
}
  • Use consistent, punctuated comments that follow existing style.
/// Tracks pending summarization requests for the compact feature.
struct PendingSummarization {
    task_id: TaskId,
    started_receiving: bool,
    buffer: String,
}
  • Favor integration tests that validate behavior end-to-end over brittle unit tests.
#[test]
fn compact_flow_creates_new_chat_with_summary() {
    // Arrange: create app, enter chat state with history.
    // Act: trigger `/compact`, simulate summarize task events, complete.
    // Assert: new ChatWidget is created and initial prompt contains the summary.
}

DONTs

  • Dont stash "{}" in a const and call .replace("{}", ...).
// ❌ Avoid
const TEMPLATE: &str = "Summary:\n\n{}";
let prompt = TEMPLATE.replace("{}", summary);
  • Dont declare helpers and supporting structs before the main types.
// ❌ Avoid putting this before `App`
fn create_compact_summary_prompt(..) -> String { /* ... */ }
  • Dont handle summarization inline inside the deepest part of the event loop.
// ❌ Avoid deep, inlined logic here
AppEvent::CodexEvent(event) => {
    if let EventMsg::AgentMessage(msg) = &event.msg { /* ... */ }
}
  • Dont match long, repetitive paths instead of importing the type.
// ❌ Avoid
match &event.msg {
    codex_core::protocol::EventMsg::AgentMessage(m) => { /* ... */ }
    _ => {}
}
  • Dont treat every AgentMessage as part of the summary.
// ❌ Avoid collecting all messages
if let EventMsg::AgentMessage(m) = &event.msg {
    pending.buffer.push_str(&m.message);
}
  • Dont alphabetize slash commands; keep them ordered by expected frequency.
// ❌ Avoid: purely alphabetical ordering
enum SlashCommand { Compact, Diff, New, Quit, ToggleMouseMode }
  • Dont keep low-signal tests that mirror implementation details or string internals.
// ❌ Avoid tests like:
assert!(COMPACT_SUMMARY_TEMPLATE.contains("{}"));
  • Dont omit periods in doc comments; match the repositorys comment style.
// ❌ Avoid missing punctuation
/// Tracks pending summarization requests