magi-code 0.105.0

Repository-aware CLI coding agent for terminal work
Documentation
use super::{ToolResult, ToolResultDisplay};
use crate::output::ToolDispatchContext;
use serde_json::{Value, json};

pub(super) struct MagiControlContext<'a> {
    pub(super) compact_enabled: &'a bool,
}

impl MagiControlContext<'_> {
    pub(super) fn run(
        &self,
        arguments: Value,
        context: ToolDispatchContext,
    ) -> anyhow::Result<ToolResult> {
        let object = arguments
            .as_object()
            .ok_or_else(|| anyhow::anyhow!("magi_control arguments must be an object"))?;
        let action = object
            .get("action")
            .and_then(Value::as_str)
            .ok_or_else(|| {
                anyhow::anyhow!("magi_control action must be `compact` or `context_usage`")
            })?;
        if object.keys().any(|key| key != "action" && key != "context") {
            anyhow::bail!("magi_control accepts only `action` and optional `context`");
        }
        match action {
            "compact" => {
                if !*self.compact_enabled {
                    anyhow::bail!("magi_control action `compact` is disabled");
                }
                if let Some(context) = object.get("context") {
                    let context = context.as_str().ok_or_else(|| {
                        anyhow::anyhow!("magi_control context must be a nonblank string")
                    })?;
                    if context.trim().is_empty() {
                        anyhow::bail!("magi_control context must be a nonblank string");
                    }
                    if context.chars().count() > super::capability::MAGI_CONTROL_CONTEXT_MAX_CHARS {
                        anyhow::bail!(
                            "magi_control context exceeds maximum length of {} characters",
                            super::capability::MAGI_CONTROL_CONTEXT_MAX_CHARS
                        );
                    }
                }
                Ok(ToolResult {
                    tool_name: crate::tools::contract::tool_name::MAGI_CONTROL.to_string(),
                    success: true,
                    content: "compaction requested; execution will continue automatically after compaction".to_string(),
                    metadata: json!({"action": "compact"}),
                    display: ToolResultDisplay::default(),
                })
            }
            "context_usage" => {
                let usage = context.context_window_usage.ok_or_else(|| {
                    anyhow::anyhow!("current context-window usage is unavailable")
                })?;
                let percentage = if usage.max_tokens == 0 {
                    0
                } else {
                    usize::try_from(
                        (usage.current_tokens as u128).saturating_mul(100)
                            / usage.max_tokens as u128,
                    )
                    .unwrap_or(usize::MAX)
                };
                Ok(ToolResult {
                    tool_name: crate::tools::contract::tool_name::MAGI_CONTROL.to_string(),
                    success: true,
                    content: format!(
                        "context window: {percentage}% used ({}/{}) tokens",
                        usage.current_tokens, usage.max_tokens
                    ),
                    metadata: json!({
                        "action": "context_usage",
                        "percentage": percentage,
                        "current_tokens": usage.current_tokens,
                        "max_tokens": usage.max_tokens,
                    }),
                    display: ToolResultDisplay::default(),
                })
            }
            _ => anyhow::bail!("magi_control action must be `compact` or `context_usage`"),
        }
    }
}