Skip to main content

codetether_agent/session/context/
derive.rs

1//! Phase-A legacy derivation: clone + experimental + enforce + pairing repair.
2
3use std::sync::Arc;
4
5use anyhow::Result;
6use tokio::sync::mpsc;
7
8use crate::provider::ToolDefinition;
9use crate::session::Session;
10use crate::session::SessionEvent;
11use crate::session::helper::compression::{CompressContext, compress_last_message_if_oversized};
12use crate::session::helper::experimental;
13
14use super::compress_step::run_compression_step;
15use super::helpers::{DerivedContext, messages_len_changed};
16
17/// Derive an ephemeral [`DerivedContext`] from `session`'s pure history.
18///
19/// The canonical [`Session::messages`] buffer is never touched —
20/// `session` is borrowed immutably.
21///
22/// # Arguments
23///
24/// * `session` — The owning session (read-only borrow).
25/// * `provider` — Caller's primary provider.
26/// * `model` — Caller's primary model identifier.
27/// * `system_prompt` — Included in token estimates.
28/// * `tools` — Tool definitions, included in token estimates.
29/// * `event_tx` — Optional channel for compaction lifecycle events.
30/// * `force_keep_last` — When `Some(n)`, skip the adaptive budget
31///   cascade and force a single [`compress_messages_keep_last`] call.
32///
33/// # Errors
34///
35/// Propagates any error from the underlying compression pipeline that
36/// the recovery cascade cannot absorb.
37///
38/// [`compress_messages_keep_last`]: crate::session::helper::compression::compress_messages_keep_last
39pub async fn derive_context(
40    session: &Session,
41    provider: Arc<dyn crate::provider::Provider>,
42    model: &str,
43    system_prompt: &str,
44    tools: &[ToolDefinition],
45    event_tx: Option<&mpsc::Sender<SessionEvent>>,
46    force_keep_last: Option<usize>,
47) -> Result<DerivedContext> {
48    let origin_len = session.messages.len();
49    let mut messages = session.messages.clone();
50    let ctx = CompressContext::from_session(session);
51
52    let step0 =
53        compress_last_message_if_oversized(&mut messages, &ctx, Arc::clone(&provider), model)
54            .await?;
55
56    experimental::apply_all(&mut messages);
57
58    let before = messages.len();
59    let step1 = run_compression_step(
60        &mut messages,
61        &ctx,
62        provider,
63        model,
64        system_prompt,
65        tools,
66        event_tx,
67        force_keep_last,
68    )
69    .await?;
70
71    experimental::pairing::repair_orphans(&mut messages);
72
73    let compressed = step0 || step1 || messages_len_changed(before, &messages);
74    Ok(DerivedContext {
75        messages,
76        origin_len,
77        compressed,
78    })
79}