use uuid::Uuid;
use super::builder::AgentService;
use crate::brain::agent::error::{AgentError, Result};
use crate::services::{MessageService, SessionService};
pub(crate) const CLEAR_MARKER_PREFIX: &str = "[CONTEXT COMPACTION: cleared by the user]";
pub(crate) const CLEAR_HINT: &str = "To continue fresh without a summary: cancel if it is \
still running, then run /clear. The history stays in the session and the agent \
starts from that point at no cost.";
pub(crate) fn clear_marker(session_title: Option<&str>) -> String {
let title = session_title
.map(str::trim)
.filter(|t| !t.is_empty())
.unwrap_or("untitled");
format!(
"{CLEAR_MARKER_PREFIX}\n\n\
The user cleared this session's context at this point. Nothing said or done \
before it is in your context. The full history is still stored in this session, \
titled '{title}'. If you need something from before, use the session_search tool: \
operation 'tail' with session '{title}' reads the last messages, operation \
'search' with a query and session '{title}' finds specific content. Fetch only \
what the task needs. Continue from the user's next message."
)
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ClearReceipt {
pub session_title: Option<String>,
pub aborted_background_compaction: bool,
}
impl ClearReceipt {
pub fn user_line(&self) -> String {
let title = self
.session_title
.as_deref()
.map(str::trim)
.filter(|t| !t.is_empty())
.map(|t| format!(" (title '{t}')"))
.unwrap_or_default();
let aborted = if self.aborted_background_compaction {
" A background compaction that was running has been cancelled."
} else {
""
};
format!(
"Context cleared. The history above stays in this session{title}; the agent \
starts fresh from here and can search it with session_search when it needs \
something. No summariser call was made.{aborted}"
)
}
}
impl AgentService {
pub async fn clear_context(&self, session_id: Uuid) -> Result<ClearReceipt> {
let aborted_background_compaction = match self.take_pending_compaction(session_id) {
Some(pending) => {
tracing::info!("/clear: aborting the background compaction in flight");
pending.abort();
true
}
None => false,
};
let session_title = SessionService::new(self.context.clone())
.get_session(session_id)
.await
.map_err(AgentError::db)?
.and_then(|s| s.title);
MessageService::new(self.context.clone())
.create_message(
session_id,
"user".to_string(),
clear_marker(session_title.as_deref()),
)
.await
.map_err(AgentError::db)?;
tracing::info!(
"/clear: context cut for session {session_id} (title={:?}, aborted_background={})",
session_title,
aborted_background_compaction
);
Ok(ClearReceipt {
session_title,
aborted_background_compaction,
})
}
}