rho-coding-agent 2.20.0

A fast Rust agent harness with a small footprint and opinionated defaults
//! Host presentation and diagnostics use the SDK's session-owned accounting.
use std::collections::HashMap;

use rho_sdk::{model::ContextUsage, ContextEstimate};

use super::InteractiveRuntime;
use crate::{app::context_report::ContextReport, diagnostics::CompactionContext};

impl InteractiveRuntime {
    pub(super) fn context_usage(&self, estimate: ContextEstimate) -> ContextUsage {
        // This remains an estimate: the request baseline can be provider-reported,
        // but assistant output and later input have only local token estimates.
        // Use the configured window, exactly as the installed compaction policy
        // does. Provider window reports are available separately in diagnostics.
        ContextUsage::estimated(
            estimate.tokens(),
            self.context_window.or(estimate.reported_context_window()),
        )
    }

    pub(super) fn record_context_estimate(&self, estimate: ContextEstimate) {
        self.diagnostics
            .record_context(self.context_usage(estimate));
        self.diagnostics.record_compaction_context(
            CompactionContext::new(estimate, self.context_window, &self.compaction),
            self.sessions.session().last_compaction_decision(),
            self.sessions.session().compaction_state(),
        );
        self.diagnostics
            .observe_prompt_tokens(estimate.provider_reported_tokens());
    }

    pub(super) fn refresh_context_usage(&mut self) {
        let estimate = self.sessions.session().context_estimate();
        self.runs.note_context_usage(self.context_usage(estimate));
        self.record_context_estimate(estimate);
    }

    /// `/context` attribution of the next request. Scans committed history,
    /// so hosts call it on demand while idle, not per frame.
    pub(crate) fn context_report(&self) -> ContextReport {
        let breakdown = self.sessions.session().context_breakdown();
        let mcp_tools: HashMap<String, String> = self
            .mcp_report
            .servers
            .iter()
            .flat_map(|server| {
                server
                    .tools()
                    .iter()
                    .map(|tool| (tool.exported_name.clone(), server.identity.clone()))
            })
            .collect();
        let window = self
            .context_window
            .or(breakdown.estimate().reported_context_window());
        ContextReport::new(
            &breakdown,
            &self.diagnostics.prompt_sources(),
            &mcp_tools,
            window,
        )
    }
}