use std::sync::Arc;
use anyhow::Result;
use crate::provider::ToolDefinition;
use crate::session::ResidencyLevel;
use crate::session::Session;
use crate::session::helper::experimental;
use crate::session::helper::token::estimate_request_tokens;
use super::derive::derive_context;
use super::helpers::DerivedContext;
use super::reset_helpers::{last_user_index, latest_reset_marker_index};
use super::reset_rebuild::rebuild_with_summary;
pub(super) async fn derive_reset(
session: &Session,
provider: Arc<dyn crate::provider::Provider>,
model: &str,
system_prompt: &str,
tools: &[ToolDefinition],
threshold_tokens: usize,
) -> Result<DerivedContext> {
let origin_len = session.messages.len();
let mut messages = session.messages.clone();
let mut dropped_ranges = Vec::new();
let mut provenance = Vec::new();
let mut base_index = 0usize;
let est = estimate_request_tokens(system_prompt, &messages, tools);
if est <= threshold_tokens {
experimental::pairing::repair_orphans(&mut messages);
return Ok(DerivedContext {
resolutions: vec![ResidencyLevel::Full; messages.len()],
dropped_ranges: Vec::new(),
provenance: vec!["reset_below_threshold".to_string()],
messages,
origin_len,
compressed: false,
});
}
if let Some(reset_idx) = latest_reset_marker_index(&messages).filter(|idx| *idx > 0) {
messages = messages.split_off(reset_idx);
base_index = reset_idx;
dropped_ranges.push((0, reset_idx));
provenance.push("reset_marker".to_string());
let anchored_est = estimate_request_tokens(system_prompt, &messages, tools);
if anchored_est <= threshold_tokens {
experimental::pairing::repair_orphans(&mut messages);
return Ok(DerivedContext {
resolutions: vec![ResidencyLevel::Full; messages.len()],
dropped_ranges,
provenance,
messages,
origin_len,
compressed: true,
});
}
}
let Some(split_idx) = last_user_index(&messages) else {
if !provenance.is_empty() {
experimental::pairing::repair_orphans(&mut messages);
return Ok(DerivedContext {
resolutions: vec![ResidencyLevel::Full; messages.len()],
dropped_ranges,
provenance,
messages,
origin_len,
compressed: true,
});
}
return derive_context(session, provider, model, system_prompt, tools, None, None).await;
};
let tail = messages.split_off(split_idx);
let prefix = std::mem::take(&mut messages);
if prefix.is_empty() {
messages = tail;
experimental::pairing::repair_orphans(&mut messages);
return Ok(DerivedContext {
resolutions: vec![ResidencyLevel::Full; messages.len()],
dropped_ranges,
provenance: if provenance.is_empty() {
vec!["reset_without_prefix".to_string()]
} else {
provenance
},
messages,
origin_len,
compressed: base_index > 0,
});
}
let prefix_len = prefix.len();
let mut derived =
rebuild_with_summary(session, &prefix, &tail, provider, model, origin_len).await?;
dropped_ranges.push((base_index, base_index + prefix_len));
if !provenance.is_empty() {
provenance.extend(derived.provenance);
derived.provenance = provenance;
}
derived.dropped_ranges = dropped_ranges;
Ok(derived)
}