Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions src-tauri/src/parser/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,19 @@ mod tests {
assert_eq!(e.entry_type, "response_item");
}

// Codex v0.130.0 (PR #21683): "research preview" text removed from startup banner.
// codex-trace reads version from session_meta.payload.cli_version — not from any
// banner text output by `codex exec`. This test confirms v0.130.0 sessions parse
// correctly and that version detection is unaffected by the banner wording change.
#[test]
fn v0130_startup_banner_research_preview_removal_does_not_affect_version_detection() {
let line = r#"{"timestamp":"2026-05-08T10:00:00Z","type":"session_meta","payload":{"id":"v0130-session","timestamp":"2026-05-08T10:00:00Z","cwd":"/tmp","cli_version":"0.130.0","model_provider":"openai"}}"#;
let e = RawEntry::parse(line).unwrap();
assert_eq!(e.entry_type, "session_meta");
assert_eq!(e.payload["cli_version"], "0.130.0");
assert_eq!(e.payload["id"], "v0130-session");
}

#[test]
fn log_db_log_writer_refactor_does_not_affect_jsonl_session_parser() {
// Codex v0.128.0 PRs #19234/#19959 refactored the internal log DB into a
Expand Down Expand Up @@ -298,4 +311,32 @@ mod tests {
let meta = RawEntry::parse(lines[0]).unwrap();
assert_eq!(meta.payload["cli_version"], "0.128.0");
}

#[test]
fn codex_v0_130_0_startup_banner_change_does_not_affect_session_parsing() {
// Codex v0.130.0 (PR #21683) removed "research preview" from the `codex exec`
// startup banner. Session JSONL files at ~/.codex/sessions/ contain structured
// data, not banner text — so this UI change has no effect on parsing. Verify
// that all standard entry types from a v0.130.0 session parse correctly.
let lines = [
r#"{"timestamp":"2026-05-08T10:00:00Z","type":"session_meta","payload":{"id":"v0130-session","timestamp":"2026-05-08T10:00:00Z","cwd":"/tmp","cli_version":"0.130.0","model_provider":"openai"}}"#,
r#"{"timestamp":"2026-05-08T10:00:01Z","type":"event_msg","payload":{"type":"task_started","turn_id":"turn-1"}}"#,
r#"{"timestamp":"2026-05-08T10:00:02Z","type":"response_item","payload":{"type":"message","role":"assistant","content":"Hello"}}"#,
r#"{"timestamp":"2026-05-08T10:00:03Z","type":"turn_context","payload":{"model":"gpt-5","cwd":"/tmp"}}"#,
r#"{"timestamp":"2026-05-08T10:00:04Z","type":"event_msg","payload":{"type":"task_complete","turn_id":"turn-1","completed_at":1746700804.0}}"#,
];
let expected_types = [
"session_meta",
"event_msg",
"response_item",
"turn_context",
"event_msg",
];
for (line, expected) in lines.iter().zip(expected_types.iter()) {
let entry = RawEntry::parse(line).expect("parse failed");
assert_eq!(entry.entry_type, *expected, "wrong type for: {line}");
}
let meta = RawEntry::parse(lines[0]).unwrap();
assert_eq!(meta.payload["cli_version"], "0.130.0");
}
}
29 changes: 28 additions & 1 deletion src-tauri/src/parser/toolcall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -962,7 +962,7 @@ fn extract_mcp_output(payload: &Value) -> Option<String> {

#[cfg(test)]
mod tests {
use super::parse_mcp_namespace;
use super::{parse_exec_function_output, parse_mcp_namespace};

#[test]
fn namespace_with_tool_prefix_keeps_full_namespace_as_server() {
Expand Down Expand Up @@ -997,4 +997,31 @@ mod tests {
assert_eq!(server, None);
assert_eq!(tool, None);
}

#[test]
fn exec_output_parsing_unaffected_by_codex_v0_130_0_banner_change() {
// Codex v0.130.0 (PR #21683) removed "research preview" from the `codex exec`
// startup banner. codex-trace must not pattern-match on banner wording — only
// stable structural markers (Output:, exit code, wall time, session id) are used.
let old_banner = "Codex - a coding agent (research preview)\nOutput:\nhello\nExit code: 0\nWall time: 0.5s\n";
let new_banner = "Codex - a coding agent\nOutput:\nhello\nExit code: 0\nWall time: 0.5s\n";

let old = parse_exec_function_output(old_banner);
let new = parse_exec_function_output(new_banner);

assert_eq!(
old.status, new.status,
"status differs between banner formats"
);
assert_eq!(old.exit_code, new.exit_code);
assert_eq!(old.duration_secs, new.duration_secs);
let old_out = old.output.unwrap_or_default();
let new_out = new.output.unwrap_or_default();
assert!(old_out.contains("hello"), "old banner output missing hello");
assert!(new_out.contains("hello"), "new banner output missing hello");
assert!(
!old_out.contains("research preview"),
"banner text leaked into output"
);
}
}