magi-code 0.96.1

Repository-aware CLI coding agent for terminal work
Documentation
use crate::{config::CodeModeToolSettings, providers::ProviderToolResult, tools::ToolCapability};
use std::collections::HashMap;

const MECHANICAL_TOOLS: &[&str] = &[
    "read",
    "grep",
    "find",
    "list_files",
    "ast_grep",
    "write",
    "hash_edit",
];
const CALL_THRESHOLD: usize = 6;
const REPEATED_TOOL_THRESHOLD: usize = 4;
const RESULT_BYTES_THRESHOLD: usize = 64 * 1024;
pub(crate) const NUDGE: &str = "Several direct tool calls/results have accumulated. If remaining work is mechanical and needs no reasoning between steps, consider code_mode to batch it and return only relevant results.";

#[derive(Debug, Default)]
pub(crate) struct DirectToolUsage {
    calls: usize,
    counts: HashMap<String, usize>,
    bytes: usize,
    nudged: bool,
    used_code_mode: bool,
}

impl DirectToolUsage {
    /// Returns the one-time batching hint; callers persist it as provider context.
    pub(crate) fn observe(
        &mut self,
        settings: &CodeModeToolSettings,
        result: &ProviderToolResult,
    ) -> Option<&'static str> {
        if result.tool_name == super::TOOL_NAME {
            self.used_code_mode = true;
        }
        if !settings.enabled || !settings.nudges_enabled || self.nudged || self.used_code_mode {
            return None;
        }
        let name = ToolCapability::from_dispatch_name(&result.tool_name)
            .map(ToolCapability::canonical_name)
            .unwrap_or(&result.tool_name);
        self.bytes = self.bytes.saturating_add(result.output.len());
        let mut repeated = 0;
        if MECHANICAL_TOOLS.contains(&name) || name.starts_with("mcp__") {
            self.calls = self.calls.saturating_add(1);
            let count = self.counts.entry(name.to_owned()).or_default();
            *count += 1;
            repeated = *count;
        }
        self.nudged = self.calls >= CALL_THRESHOLD
            || repeated >= REPEATED_TOOL_THRESHOLD
            || self.bytes >= RESULT_BYTES_THRESHOLD;
        self.nudged.then_some(NUDGE)
    }
}