diff --git a/src-tauri/src/parser/entry.rs b/src-tauri/src/parser/entry.rs index 09c348d..5907d0e 100644 --- a/src-tauri/src/parser/entry.rs +++ b/src-tauri/src/parser/entry.rs @@ -607,4 +607,47 @@ mod tests { assert_eq!(meta.payload["cli_version"], "0.134.0"); assert_eq!(meta.payload["profile"], "default"); } + + // Codex v0.133.0 (PR #22709): TurnContextItem fields trimmed. + // turn_context payloads now carry only the fields still used internally; previously + // populated fields like cwd and effort may be absent. The loosely-typed RawEntry + // model must parse both old (extra fields) and new (trimmed) payloads without error. + + #[test] + fn v0133_turn_context_trimmed_payload_parses_as_turn_context_entry() { + // v0.133.0 turn_context with minimal payload — only model is present. + let line = r#"{"timestamp":"2026-05-21T10:00:02Z","type":"turn_context","payload":{"model":"gpt-5"}}"#; + let e = RawEntry::parse(line).expect("turn_context with minimal payload must parse"); + assert_eq!(e.entry_type, "turn_context"); + assert_eq!(e.payload["model"], "gpt-5"); + // cwd and effort are absent — must not panic + assert!(e.payload.get("cwd").is_none()); + assert!(e.payload.get("effort").is_none()); + } + + #[test] + fn v0133_all_standard_entry_types_parse_correctly() { + // Regression guard: all standard JSONL entry types must parse under v0.133.0. + // turn_context payload is trimmed — only model is present (PR #22709). + let lines = [ + r#"{"timestamp":"2026-05-21T10:00:00Z","type":"session_meta","payload":{"id":"v0133-session","timestamp":"2026-05-21T10:00:00Z","cwd":"/tmp","cli_version":"0.133.0","model_provider":"openai"}}"#, + r#"{"timestamp":"2026-05-21T10:00:01Z","type":"event_msg","payload":{"type":"task_started","turn_id":"turn-1"}}"#, + r#"{"timestamp":"2026-05-21T10:00:02Z","type":"response_item","payload":{"type":"message","role":"assistant","content":"Hello"}}"#, + r#"{"timestamp":"2026-05-21T10:00:03Z","type":"turn_context","payload":{"model":"gpt-5"}}"#, + r#"{"timestamp":"2026-05-21T10:00:04Z","type":"event_msg","payload":{"type":"task_complete","turn_id":"turn-1","completed_at":1748167204.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.133.0"); + } } diff --git a/src-tauri/src/parser/session.rs b/src-tauri/src/parser/session.rs index 80a1ba8..9da5e3f 100644 --- a/src-tauri/src/parser/session.rs +++ b/src-tauri/src/parser/session.rs @@ -911,4 +911,38 @@ mod tests { assert_eq!(session.turns.len(), 1); assert!(!session.is_ongoing); } + + // Codex v0.133.0 (PR #22709): TurnContextItem fields trimmed. + // turn_context payloads now carry only the model field; cwd and effort are no longer + // emitted. Sessions from v0.133.0+ must parse correctly with the reduced payload. + + #[test] + fn v0133_turn_context_trimmed_fields_session_parses_correctly() { + // v0.133.0 session where turn_context has only model — cwd and effort are absent. + // Verifies the parser extracts model from the trimmed payload and does not panic + // on the missing fields. + let tmp = tempdir().unwrap(); + let path = tmp.path().join("rollout-2026-05-21T10-00-00-v0133.jsonl"); + std::fs::write( + &path, + [ + r#"{"timestamp":"2026-05-21T10:00:00Z","type":"session_meta","payload":{"id":"v0133-turn-ctx","timestamp":"2026-05-21T10:00:00Z","cwd":"/workspace","cli_version":"0.133.0","model_provider":"openai"}}"#, + r#"{"timestamp":"2026-05-21T10:00:01Z","type":"event_msg","payload":{"type":"task_started","turn_id":"turn-1"}}"#, + r#"{"timestamp":"2026-05-21T10:00:02Z","type":"response_item","payload":{"type":"message","role":"assistant","content":"Done"}}"#, + r#"{"timestamp":"2026-05-21T10:00:03Z","type":"turn_context","payload":{"model":"gpt-5"}}"#, + r#"{"timestamp":"2026-05-21T10:00:04Z","type":"event_msg","payload":{"type":"task_complete","turn_id":"turn-1","completed_at":1748167204.0}}"#, + ] + .join("\n"), + ) + .unwrap(); + + let session = parse_session(&path).unwrap(); + assert_eq!(session.id, "v0133-turn-ctx"); + assert_eq!(session.cli_version.as_deref(), Some("0.133.0")); + assert_eq!(session.turns.len(), 1); + assert_eq!(session.turns[0].model.as_deref(), Some("gpt-5")); + // cwd and effort absent in turn_context — must not panic + assert!(session.turns[0].reasoning_effort.is_none()); + assert!(!session.is_ongoing); + } }