codetether_agent/tool/
context_budget.rs1use 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
14pub 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}