llm_chain/tools/tools/
python.rs1use crate::tools::description::{Describe, Format, ToolDescription};
2use crate::tools::tool::{Tool, ToolError};
3use async_trait::async_trait;
4use serde::{Deserialize, Serialize};
5use std::process::Command;
6use thiserror::Error;
7
8pub struct PythonTool {}
9
10impl PythonTool {
11 pub fn new() -> Self {
12 PythonTool {}
13 }
14}
15
16impl Default for PythonTool {
17 fn default() -> Self {
18 Self::new()
19 }
20}
21
22#[derive(Serialize, Deserialize)]
23pub struct PythonToolInput {
24 code: String,
25}
26
27#[derive(Serialize, Deserialize)]
28pub struct PythonToolOutput {
29 result: String,
30 stderr: String,
31}
32
33impl Describe for PythonToolInput {
34 fn describe() -> Format {
35 vec![("code", "The Python code to execute.").into()].into()
36 }
37}
38
39impl Describe for PythonToolOutput {
40 fn describe() -> Format {
41 vec![
42 ("result", "The result of the executed Python code.").into(),
43 ("stderr", "The stderr output of the Python code execution.").into(),
44 ]
45 .into()
46 }
47}
48
49#[derive(Debug, Error)]
50pub enum PythonToolError {
51 #[error(transparent)]
52 YamlError(#[from] serde_yaml::Error),
53 #[error(transparent)]
54 IOError(#[from] std::io::Error),
55}
56
57impl ToolError for PythonToolError {}
58
59#[async_trait]
60impl Tool for PythonTool {
61 type Input = PythonToolInput;
62 type Output = PythonToolOutput;
63 type Error = PythonToolError;
64
65 async fn invoke_typed(&self, input: &Self::Input) -> Result<Self::Output, Self::Error> {
66 let output = Command::new("python3")
67 .arg("-c")
68 .arg(&input.code)
69 .output()?;
70 Ok(PythonToolOutput {
71 result: String::from_utf8(output.stdout).unwrap(),
72 stderr: String::from_utf8(output.stderr).unwrap(),
73 })
74 }
75
76 fn description(&self) -> ToolDescription {
77 ToolDescription::new(
78 "PythonTool",
79 "A tool that executes Python code.",
80 "Use this to execute Python code to solve your goals",
81 PythonToolInput::describe(),
82 PythonToolOutput::describe(),
83 )
84 }
85}