a3s-code-core 5.2.7

A3S Code Core - Embeddable AI agent library with tool execution
Documentation
use anyhow::Result;
use async_trait::async_trait;
use serde_json::Value;

use crate::tools::{Tool, ToolContext, ToolOutput};

use super::{
    code_intelligence_error, format, invalid_argument, provider, query_capabilities,
    structured_success, unavailable,
};

pub(super) struct CodeDiagnosticsTool;

#[async_trait]
impl Tool for CodeDiagnosticsTool {
    fn name(&self) -> &str {
        "code_diagnostics"
    }

    fn description(&self) -> &str {
        "Return language diagnostics for saved workspace code. Provide path for one document or omit it for a bounded manifest-backed workspace query. For document queries only, an empty items array means diagnostics were received and cleared. Workspace queries start relevant language runtimes; truncated can also mean partial language coverage."
    }

    fn parameters(&self) -> Value {
        serde_json::json!({
            "type": "object",
            "additionalProperties": false,
            "properties": {
                "path": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Optional saved workspace document path. Omit for workspace diagnostics."
                }
            },
            "examples": [{}, {"path": "src/lib.rs"}]
        })
    }

    fn capabilities(&self, _args: &Value) -> crate::tools::ToolCapabilities {
        query_capabilities()
    }

    async fn execute(&self, args: &Value, ctx: &ToolContext) -> Result<ToolOutput> {
        let path = match args.get("path") {
            Some(Value::String(path)) if !path.trim().is_empty() => {
                match ctx.resolve_workspace_path(path) {
                    Ok(path) => Some(path),
                    Err(error) => {
                        return Ok(invalid_argument(format!(
                            "failed to resolve workspace path: {error}"
                        )))
                    }
                }
            }
            Some(Value::String(_)) => return Ok(invalid_argument("path must not be empty")),
            Some(_) => return Ok(invalid_argument("path must be a string")),
            None => None,
        };
        let Some(provider) = provider(ctx) else {
            return Ok(unavailable("diagnostics"));
        };
        match provider
            .diagnostics(path.as_ref(), ctx.cancellation_token())
            .await
        {
            Ok(result) => Ok(structured_success(format::diagnostics(result))),
            Err(error) => Ok(code_intelligence_error("diagnostics", error)),
        }
    }
}