bctx-weave 0.1.29

bctx-weave — FilterMesh lens pipeline, CLI interception, domain compression
Documentation
use super::{Lens, LensContext, LensId, LensOutput};
use forge::budget::estimator::TokenEstimator;

/// Narrow: aggressively truncate to fit the token budget.
/// Keeps the first 60% and last 40% of the content (LITM-aware).
pub struct NarrowLens;

impl Lens for NarrowLens {
    fn id(&self) -> LensId {
        LensId::Narrow
    }

    fn apply(&self, input: &str, ctx: &LensContext) -> LensOutput {
        let tokens_before = TokenEstimator::count_nonblocking(input);
        let budget = ctx.budget.remaining().min(ctx.budget.limit);

        if tokens_before <= budget {
            return LensOutput {
                content: input.to_string(),
                tokens_before,
                tokens_after: tokens_before,
                applied: vec!["narrow".into()],
            };
        }

        let lines: Vec<&str> = input.lines().collect();
        if lines.is_empty() {
            return LensOutput::passthrough(input);
        }

        // Aim for target lines proportional to budget
        let ratio = budget as f64 / tokens_before as f64;
        let target_lines = ((lines.len() as f64 * ratio) as usize).max(10);

        let head = (target_lines * 6 / 10).max(5);
        let tail = (target_lines * 4 / 10).max(5);

        let content = if lines.len() <= head + tail {
            lines.join("\n")
        } else {
            let head_lines = &lines[..head];
            let tail_lines = &lines[lines.len() - tail..];
            let skipped = lines.len() - head - tail;
            format!(
                "{}\n... [{skipped} lines omitted] ...\n{}",
                head_lines.join("\n"),
                tail_lines.join("\n")
            )
        };

        let tokens_after = TokenEstimator::count_nonblocking(&content);
        LensOutput {
            content,
            tokens_before,
            tokens_after,
            applied: vec!["narrow".into()],
        }
    }
}