use crate::repl;
use crate::tool_definition;
use serde_json::json;
pub struct Tool<'a> {
repl: &'a repl::Repl,
}
impl<'a> Tool<'a> {
pub fn new(repl: &'a repl::Repl) -> Self {
Self { repl }
}
pub fn definition(&self) -> genai::chat::Tool {
genai::chat::Tool::new(tool_definition::NAME)
.with_description(tool_definition::DESCRIPTION)
.with_schema(tool_definition::json_schema())
}
pub fn call_tool(&self, tool_call: &genai::chat::ToolCall) -> genai::chat::ToolResponse {
if tool_call.fn_name != tool_definition::NAME {
return Self::build_error_response(
tool_call.call_id.clone(),
format!(
"Unknown tool: {}. Expected: {}",
tool_call.fn_name,
tool_definition::NAME
),
);
}
let source_code = match &tool_call.fn_arguments[tool_definition::PARAM_SOURCE_CODE] {
serde_json::Value::String(s) => s,
_ => {
return Self::build_error_response(
tool_call.call_id.clone(),
format!(
"Missing or invalid parameter: {}",
tool_definition::PARAM_SOURCE_CODE
),
);
}
};
let eval_outcome = match self.repl.eval(source_code) {
Ok(outcome) => outcome,
Err(err) => {
return Self::build_error_response(
tool_call.call_id.clone(),
format!("REPL evaluation failed: {}", err),
);
}
};
genai::chat::ToolResponse::new(
tool_call.call_id.clone(),
json!({
"output": eval_outcome.output.join("\n"),
"result": match eval_outcome.result {
Ok(values) => values.join("\n"),
Err(err) => format!("error: {}", err)
}
})
.to_string(),
)
}
fn build_error_response(call_id: String, error_message: String) -> genai::chat::ToolResponse {
genai::chat::ToolResponse::new(call_id, json!({ "error": error_message }).to_string())
}
}