use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use crate::config::ProjectConfig;
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct AnthropicTool {
pub name: String,
pub description: String,
#[serde(rename = "input_schema")]
pub input_schema: InputSchema,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct OpenAITool {
pub name: String,
pub description: String,
#[serde(rename = "type")]
pub tool_type: String,
pub function: OpenAIToolFunction,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct OpenAIToolFunction {
pub description: String,
pub name: String,
pub parameters: InputSchema,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct InputSchema {
#[serde(rename = "type")]
pub schema_type: String,
pub properties: HashMap<String, PropertySchema>,
pub required: Vec<String>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct PropertySchema {
#[serde(rename = "type")]
pub property_type: String,
pub description: String,
}
pub struct Tooler {
tools: Vec<Box<dyn ToolTrait>>,
}
trait ToolTrait: Send + Sync {
fn to_json(&self) -> serde_json::Value;
}
impl ToolTrait for AnthropicTool {
fn to_json(&self) -> serde_json::Value {
serde_json::to_value(self).unwrap()
}
}
impl ToolTrait for OpenAITool {
fn to_json(&self) -> serde_json::Value {
serde_json::to_value(self).unwrap()
}
}
impl Tooler {
pub fn new() -> Self {
let config = match ProjectConfig::load() {
Ok(c) => c,
Err(_) => ProjectConfig::default()
};
if config.base_url.contains("anthropic.com") {
Tooler {
tools: vec![
Box::new(Self::read_file_anthropic_tool()),
Box::new(Self::write_file_anthropic_tool()),
Box::new(Self::execute_anthropic_tool()),
Box::new(Self::compile_check_tool()),
]
}
} else {
Tooler {
tools: vec![
Box::new(Self::read_file_openai_tool()),
Box::new(Self::write_file_openai_tool()),
Box::new(Self::execute_openai_tool()),
Box::new(Self::compile_check_openai_tool()),
]
}
}
}
fn read_file_anthropic_tool() -> AnthropicTool {
AnthropicTool {
name: "read_file".to_string(),
description: "Read file as string using path relative to root directory of project.".to_string(),
input_schema: InputSchema {
schema_type: "object".to_string(),
properties: {
let mut map = HashMap::new();
map.insert(
"path".to_string(),
PropertySchema {
property_type: "string".to_string(),
description: "The file path relative to the project root directory".to_string(),
},
);
map
},
required: vec!["path".to_string()],
},
}
}
fn read_file_openai_tool() -> OpenAITool {
OpenAITool {
name: "read_file".to_string(),
description: "Read file as string using path relative to root directory of project.".to_string(),
tool_type: "function".to_string(),
function: OpenAIToolFunction {
name: "read_file".to_string(),
description: "Read file as string using path relative to root directory of project.".to_string(),
parameters: InputSchema {
schema_type: "object".to_string(),
properties: {
let mut map = HashMap::new();
map.insert(
"path".to_string(),
PropertySchema {
property_type: "string".to_string(),
description: "The file path relative to the project root directory".to_string(),
},
);
map
},
required: vec!["path".to_string()],
},
},
}
}
fn write_file_anthropic_tool() -> AnthropicTool {
AnthropicTool {
name: "write_file".to_string(),
description: "Write string to file at path relative to root directory of project.".to_string(),
input_schema: InputSchema {
schema_type: "object".to_string(),
properties: {
let mut map = HashMap::new();
map.insert(
"path".to_string(),
PropertySchema {
property_type: "string".to_string(),
description: "The file path relative to the project root directory".to_string(),
},
);
map.insert(
"content".to_string(),
PropertySchema {
property_type: "string".to_string(),
description: "The content to write to the file".to_string(),
},
);
map
},
required: vec!["path".to_string(), "content".to_string()],
},
}
}
fn write_file_openai_tool() -> OpenAITool {
OpenAITool {
name: "write_file".to_string(),
description: "Write string to file at path relative to root directory of project.".to_string(),
tool_type: "function".to_string(),
function: OpenAIToolFunction {
name: "write_file".to_string(),
description: "Write string to file at path relative to root directory of project.".to_string(),
parameters: InputSchema {
schema_type: "object".to_string(),
properties: {
let mut map = HashMap::new();
map.insert(
"path".to_string(),
PropertySchema {
property_type: "string".to_string(),
description: "The file path relative to the project root directory".to_string(),
},
);
map.insert(
"content".to_string(),
PropertySchema {
property_type: "string".to_string(),
description: "The content to write to the file".to_string(),
},
);
map
},
required: vec!["path".to_string(), "content".to_string()],
},
},
}
}
fn execute_anthropic_tool() -> AnthropicTool {
AnthropicTool {
name: "execute".to_string(),
description: "Execute bash statements as a single string..".to_string(),
input_schema: InputSchema {
schema_type: "object".to_string(),
properties: {
let mut map = HashMap::new();
map.insert(
"statement".to_string(),
PropertySchema {
property_type: "string".to_string(),
description: "The bash statement to be executed.".to_string(),
},
);
map
},
required: vec!["statement".to_string()],
},
}
}
fn execute_openai_tool() -> OpenAITool {
OpenAITool {
name: "execute".to_string(),
description: "Execute bash statements as a single string..".to_string(),
tool_type: "function".to_string(),
function: OpenAIToolFunction {
name: "execute".to_string(),
description: "Execute bash statements as a single string..".to_string(),
parameters: InputSchema {
schema_type: "object".to_string(),
properties: {
let mut map = HashMap::new();
map.insert(
"statement".to_string(),
PropertySchema {
property_type: "string".to_string(),
description: "The bash statement to be executed.".to_string(),
},
);
map
},
required: vec!["statement".to_string()],
},
},
}
}
fn compile_check_tool() -> AnthropicTool {
AnthropicTool {
name: "compile_check".to_string(),
description: "Check if project compiles or runs without error.".to_string(),
input_schema: InputSchema {
schema_type: "object".to_string(),
properties: {
let mut map = HashMap::new();
map.insert(
"cmd".to_string(),
PropertySchema {
property_type: "string".to_string(),
description: "The command to check for compiler/interpreter errors.".to_string(),
},
);
map
},
required: vec!["cmd".to_string()],
},
}
}
fn compile_check_openai_tool() -> OpenAITool {
OpenAITool {
name: "compile_check".to_string(),
description: "Check if project compiles or runs without error.".to_string(),
tool_type: "function".to_string(),
function: OpenAIToolFunction {
name: "compile_check".to_string(),
description: "Check if project compiles or runs without error.".to_string(),
parameters: InputSchema {
schema_type: "object".to_string(),
properties: {
let mut map = HashMap::new();
map.insert(
"cmd".to_string(),
PropertySchema {
property_type: "string".to_string(),
description: "The command to check for compiler/interpreter errors.".to_string(),
},
);
map
},
required: vec!["cmd".to_string()],
},
},
}
}
pub fn get_tools_json(&self) -> Result<serde_json::Value, serde_json::Error> {
let tools_json: Vec<serde_json::Value> = self.tools
.iter()
.map(|tool| tool.to_json())
.collect();
serde_json::to_value(tools_json)
}
}