openfunctions_rs/core/
tool.rs1use crate::models::ToolDefinition;
7use crate::parser::ToolParser;
8use anyhow::Result;
9use serde::{Deserialize, Serialize};
10use std::path::{Path, PathBuf};
11
12#[derive(Debug, Clone)]
17pub struct Tool {
18 pub name: String,
20
21 pub path: PathBuf,
23
24 pub language: ToolLanguage,
26
27 pub definition: ToolDefinition,
29
30 pub declaration: crate::core::function::FunctionDeclaration,
32}
33
34impl Tool {
35 pub async fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
40 let path = path.as_ref().to_path_buf();
41 let name = path
42 .file_stem()
43 .ok_or_else(|| anyhow::anyhow!("Invalid tool filename: {}", path.display()))?
44 .to_string_lossy()
45 .to_string();
46
47 let language = ToolLanguage::from_extension(
48 path.extension().and_then(|ext| ext.to_str()).unwrap_or(""),
49 )?;
50
51 let content = tokio::fs::read_to_string(&path).await?;
52 let parser = ToolParser::new(language);
53 let definition = parser.parse(&content)?;
54
55 let declaration = definition.to_function_declaration(&name)?;
56
57 Ok(Self {
58 name,
59 path,
60 language,
61 definition,
62 declaration,
63 })
64 }
65
66 pub fn get_command(&self) -> Vec<String> {
68 match self.language {
69 ToolLanguage::Bash => vec!["bash".to_string(), self.path.to_string_lossy().to_string()],
70 ToolLanguage::JavaScript => {
71 vec!["node".to_string(), self.path.to_string_lossy().to_string()]
72 }
73 ToolLanguage::Python => vec![
74 "python".to_string(),
75 self.path.to_string_lossy().to_string(),
76 ],
77 }
78 }
79}
80
81#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
83#[serde(rename_all = "lowercase")]
84pub enum ToolLanguage {
85 Bash,
87 JavaScript,
89 Python,
91}
92
93impl ToolLanguage {
94 pub fn from_extension(ext: &str) -> Result<Self> {
96 match ext {
97 "sh" => Ok(Self::Bash),
98 "js" => Ok(Self::JavaScript),
99 "py" => Ok(Self::Python),
100 _ => anyhow::bail!("Unsupported file extension for a tool: {}", ext),
101 }
102 }
103
104 pub fn extension(&self) -> &'static str {
106 match self {
107 Self::Bash => "sh",
108 Self::JavaScript => "js",
109 Self::Python => "py",
110 }
111 }
112}
113
114impl std::fmt::Display for ToolLanguage {
115 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
116 f.write_str(match self {
117 Self::Bash => "bash",
118 Self::JavaScript => "javascript",
119 Self::Python => "python",
120 })
121 }
122}