//! Apply live exploration compatibility to replay and repair groups split by history pages. use super::tools::CommandHistory; use crate::exec_cell::ExecCell; use crate::history_cell::HistoryCell; use codex_app_server_protocol::ThreadItemPayload; use codex_app_server_protocol::Turn; use std::sync::Arc; pub(crate) fn join_exploration_groups( older: &Arc, newer: &Arc, turns: &[Turn], ) -> Option> { let older = older.as_any().downcast_ref::()?; let newer = newer.as_any().downcast_ref::()?; let items = adjacent_items(older, newer, turns)?; let mut group = completed_group(items)?; group.group.details = newer.group.details.clone(); group .group .details .prepend(older.group.details.clone(), older.group.calls.len()); Some(Arc::new(group)) } pub(crate) fn older_exploration_group( older: &dyn HistoryCell, newer: &ExecCell, turns: &[Turn], ) -> Option { let older = older.as_any().downcast_ref::()?; let items = adjacent_items(older, newer, turns)?; let older_items = items .iter() .filter(|entry| !matches!(&entry.payload, ThreadItemPayload::Reasoning { .. })) .take(older.group.calls.len()) .cloned() .collect::>(); let mut group = completed_group(&older_items)?; group.group.details = older.group.details.clone(); Some(group) } fn adjacent_items<'a>( older: &ExecCell, newer: &ExecCell, turns: &'a [Turn], ) -> Option<&'a [codex_app_server_protocol::ThreadItem]> { if !older.is_exploring_cell() || older.should_flush() || !newer.is_exploring_cell() { return None; } let ids = older .iter_calls() .chain(newer.iter_calls()) .map(|call| call.call_id.as_str()) .collect::>(); super::computer_groups::adjacent_activity_items(&ids, turns) } pub(super) fn completed_group(items: &[codex_app_server_protocol::ThreadItem]) -> Option { let mut group: Option = None; for entry in items { let item = &entry.payload; if matches!(item, ThreadItemPayload::Reasoning { .. }) { continue; } let call = CommandHistory::from_item(item.clone())?.into_cell(); if !call.is_exploring_cell() { return None; } if let Some(group) = &mut group { group.append_completed(call).ok()?; } else { group = Some(call); } } group }