use super::*;
fn source_extent(
groups: &BTreeMap<u64, MessageGroup>,
source: &SessionSourceRange,
) -> Option<SessionSourceRange> {
let mut covered = groups
.values()
.filter(|group| source.contains(group.producer_seq));
let mut extent = covered.next()?.logical_source.clone();
for group in covered {
extent.first_session_seq = extent
.first_session_seq
.min(group.logical_source.first_session_seq);
extent.last_session_seq = extent
.last_session_seq
.max(group.logical_source.last_session_seq);
}
Some(extent)
}
pub(super) fn can_replace_source(
groups: &BTreeMap<u64, MessageGroup>,
records: &[AgentSessionRecord],
source: &SessionSourceRange,
) -> bool {
let Some(extent) = source_extent(groups, source) else {
return false;
};
let crosses_group = groups.values().any(|group| {
!source.contains(group.producer_seq)
&& group.logical_source.first_session_seq <= extent.last_session_seq
&& extent.first_session_seq <= group.logical_source.last_session_seq
});
let crosses_protected_record = records.iter().any(|record| {
extent.contains(record.session_seq)
&& match &record.payload {
AgentSessionEvent::SkillLoaded { .. }
| AgentSessionEvent::EffectUncertaintyCommitted { .. } => true,
AgentSessionEvent::ToolExchangeCommitted {
retained_artifacts, ..
} => !retained_artifacts.is_empty(),
_ => false,
}
});
!crosses_group && !crosses_protected_record
}
pub(super) fn summary_group(
groups: &BTreeMap<u64, MessageGroup>,
source: &SessionSourceRange,
producer_seq: u64,
summary: &ModelMessage,
pinned: bool,
active_compactable: bool,
) -> Result<MessageGroup, SessionContextError> {
let logical_source = source_extent(groups, source).ok_or_else(|| {
SessionContextError::Compaction("summary source has no live Context groups".to_owned())
})?;
let mut source_ranges: Vec<SessionSourceRange> = Vec::new();
for producer in groups
.values()
.filter(|group| source.contains(group.producer_seq))
{
if let Some(last) = source_ranges
.last_mut()
.filter(|last| last.last_session_seq.checked_add(1) == Some(producer.producer_seq))
{
last.last_session_seq = producer.producer_seq;
} else {
source_ranges.push(single_range(producer.producer_seq));
}
}
Ok(MessageGroup {
key: producer_seq,
producer_seq,
source_ranges,
logical_source,
messages: vec![summary.clone()],
pinned,
active_compactable,
})
}
#[cfg(test)]
mod tests;