Skip to main content

codetether_agent/tool/
context_budget.rs

1//! `context_budget`: report context window budget status.
2//!
3//! Returns current L_working, L_effective, recently elided ranges,
4//! and the session's bucket projection. No provider call needed —
5//! pure read from the session's summary index and page sidecar.
6
7use super::context_helpers::load_latest_session;
8use super::{Tool, ToolResult};
9use crate::session::pages::PageKind;
10use anyhow::Result;
11use async_trait::async_trait;
12use serde_json::{Value, json};
13
14/// Context budget tool.
15pub struct ContextBudgetTool;
16
17#[async_trait]
18impl Tool for ContextBudgetTool {
19    fn id(&self) -> &str {
20        "context_budget"
21    }
22    fn name(&self) -> &str {
23        "ContextBudget"
24    }
25
26    fn description(&self) -> &str {
27        "Report the current context window budget: messages count, \
28         cached summaries, page distribution, and remaining capacity. \
29         Call this to understand how much room is left before the next \
30         compression or reset. Returns L_working (current transcript \
31         length) and L_effective (with summarization multiplier)."
32    }
33
34    fn parameters(&self) -> Value {
35        json!({ "type": "object", "properties": {} })
36    }
37
38    async fn execute(&self, _args: Value) -> Result<ToolResult> {
39        let session = match load_latest_session().await {
40            Ok(Some(s)) => s,
41            Ok(None) => return Ok(ToolResult::error("No active session found.")),
42            Err(e) => return Ok(ToolResult::error(&format!("Failed to load session: {e}"))),
43        };
44        let total = session.messages.len();
45        let cached = session.summary_index.len();
46        let pinned = session
47            .pages
48            .iter()
49            .filter(|p| matches!(p, PageKind::Constraint | PageKind::Bootstrap))
50            .count();
51        let output = format!(
52            "L_working={total} messages, cached_summaries={cached}, \
53             pinned_pages={pinned}, L_effective≈{eff}",
54            eff = total + cached * 50,
55        );
56        Ok(ToolResult::success(output))
57    }
58}