diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7ac276d..f54a59e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,7 @@ name: CI on: push: - branches: [main, 'feat/**', 'fix/**'] + branches: [main, dev, 'feat/**', 'fix/**'] pull_request: branches: [main] @@ -38,4 +38,4 @@ jobs: curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendMessage" \ -d chat_id="${TELEGRAM_CHAT_ID}" \ -d parse_mode="HTML" \ - -d text="❌ CI failed on ${{ github.ref_name }}%0A${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + -d text="❌ CI failed on ${{ github.ref_name }}%0A${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" diff --git a/Cargo.toml b/Cargo.toml index 678be4a..4efc2f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "eullm-agent" -version = "0.1.6" +version = "0.1.7" edition = "2021" license = "Apache-2.0" description = "EULLM Agent — autonomous ReAct agent with multi-provider LLM support" diff --git a/src/modules/builtin.rs b/src/modules/builtin.rs index a0dab73..be9a1fd 100644 --- a/src/modules/builtin.rs +++ b/src/modules/builtin.rs @@ -12,6 +12,7 @@ fn ocr() -> ModuleManifest { version: "1.0", install_linux: vec!["sudo apt-get install -y tesseract-ocr".into()], install_macos: vec!["brew install tesseract".into()], + install_windows: vec!["choco install tesseract -y".into()], tools: vec![ModuleToolSpec { name: "ocr_image".into(), description: "Extract text from an image file using OCR.".into(), @@ -41,6 +42,7 @@ fn pdf() -> ModuleManifest { version: "1.0", install_linux: vec!["sudo apt-get install -y poppler-utils".into()], install_macos: vec!["brew install poppler".into()], + install_windows: vec!["choco install poppler -y".into()], tools: vec![ModuleToolSpec { name: "pdf_to_text".into(), description: "Extract all text content from a PDF file".into(), diff --git a/src/modules/mod.rs b/src/modules/mod.rs index cd13b8b..3fdcc8d 100644 --- a/src/modules/mod.rs +++ b/src/modules/mod.rs @@ -19,12 +19,26 @@ pub struct ModuleManifest { pub name: String, pub description: String, pub version: &'static str, + #[allow(dead_code)] pub install_linux: Vec, #[allow(dead_code)] pub install_macos: Vec, + #[allow(dead_code)] + pub install_windows: Vec, pub tools: Vec, } +impl ModuleManifest { + pub fn install_commands(&self) -> &[String] { + #[cfg(target_os = "macos")] + return &self.install_macos; + #[cfg(target_os = "windows")] + return &self.install_windows; + #[cfg(not(any(target_os = "macos", target_os = "windows")))] + return &self.install_linux; + } +} + #[derive(Debug, Serialize, Deserialize, Default)] pub struct ModuleState { pub installed: HashSet, diff --git a/src/tools/module_tool.rs b/src/tools/module_tool.rs index 35c4c7c..3a7acb9 100644 --- a/src/tools/module_tool.rs +++ b/src/tools/module_tool.rs @@ -1,12 +1,30 @@ use anyhow::Result; use async_trait::async_trait; use serde_json::{json, Value}; +use std::process::Output; use std::sync::{Arc, Mutex}; use crate::llm::ToolDefinition; use crate::modules::{ModuleRegistry, ModuleToolSpec}; use super::{Tool, ToolRegistry}; +/// Runs a shell command using the platform-appropriate shell. +async fn run_shell(cmd: &str) -> Result { + #[cfg(target_os = "windows")] + let out = tokio::process::Command::new("cmd") + .arg("/C") + .arg(cmd) + .output() + .await?; + #[cfg(not(target_os = "windows"))] + let out = tokio::process::Command::new("sh") + .arg("-c") + .arg(cmd) + .output() + .await?; + Ok(out) +} + /// Executes a single module-defined tool via shell command template substitution. pub struct ModuleTool { spec: ModuleToolSpec, @@ -41,12 +59,7 @@ impl Tool for ModuleTool { } } - let output = tokio::process::Command::new("sh") - .arg("-c") - .arg(&cmd) - .output() - .await?; - + let output = run_shell(&cmd).await?; let stdout = String::from_utf8_lossy(&output.stdout).to_string(); let stderr = String::from_utf8_lossy(&output.stderr).to_string(); @@ -162,18 +175,9 @@ impl Tool for InstallModuleTool { anyhow::anyhow!("Unknown module: '{}'. Use list_modules to see available modules.", name) })?; - #[cfg(target_os = "macos")] - let commands = &manifest.install_macos; - #[cfg(not(target_os = "macos"))] - let commands = &manifest.install_linux; - - for cmd in commands { + for cmd in manifest.install_commands() { tracing::info!("module install: {cmd}"); - let output = tokio::process::Command::new("sh") - .arg("-c") - .arg(cmd) - .output() - .await?; + let output = run_shell(cmd).await?; if !output.status.success() { let stderr = String::from_utf8_lossy(&output.stderr); return Err(anyhow::anyhow!(