pprog 0.0.5

An LLM pair programming server with web interface
use std::fs;
use std::process::Command;
use anyhow::Result;

use crate::config::ProjectConfig;

pub struct Tools;

impl Tools {
    fn read_file(path: &str) -> Result<String> {
        Ok(fs::read_to_string(path)?)
    }

    fn write_file(path: &str, content: &str) -> Result<()> {
        Ok(fs::write(path, content)?)
    }

    fn execute(statement: &str) -> Result<String> {
        let output = Command::new("bash")
            .arg("-c")
            .arg(statement)
            .output()?;

        Ok(String::from_utf8(output.stdout)? + &String::from_utf8(output.stderr)?)
    }

    fn compile_check() -> Result<String, anyhow::Error> {
        let config = ProjectConfig::load().map_err(|e| anyhow::anyhow!("{}", e))?;

        let output = Command::new("bash")
            .arg("-c")
            .arg(config.check_cmd)
            .output()?;

        Ok(String::from_utf8(output.stdout)? + &String::from_utf8(output.stderr)?)
    }

    pub fn handle_tool_use(name: &String, inputs: &serde_json::Value) -> Result<String, anyhow::Error> {
        match name.as_str() {
            "read_file" => {
                let path = inputs.get("path")
                    .and_then(|v| v.as_str())
                    .ok_or_else(|| anyhow::Error::msg("Missing or invalid 'path' input".to_string()))?;

                Tools::read_file(path)
            },
            "write_file" => {
                let path = inputs
                    .get("path")
                    .and_then(|v| v.as_str())
                    .ok_or_else(|| anyhow::Error::msg("Missing or invalid 'path' input".to_string()))?;

                let content = inputs
                    .get("content")
                    .and_then(|v| v.as_str())
                    .ok_or_else(|| anyhow::Error::msg("Missing or invalid 'content' input".to_string()))?;

                Tools::write_file(path, content)?;
                Ok("File written successfully".to_string())
            },
            "execute" => {
                let statement = inputs
                    .get("statement")
                    .and_then(|v| v.as_str())
                    .ok_or_else(|| anyhow::Error::msg("Missing or invalid 'statement' input".to_string()))?;

                Tools::execute(statement)
            },
            "compile_check" => {
                match Tools::compile_check() {
                    Ok(output) => {
                        println!("compile output: {}", &output);
                        return Ok(output);
                    },
                    Err(e) => return Err(anyhow::Error::msg(format!("Error doing compile check: {}", e.to_string()))),
                };
            },
            _ => Err(anyhow::Error::msg(format!("Invalid tool name: {}", name))),
        }
    }
}