swiftide_core/chat_completion/
tools.rs

1use derive_builder::Builder;
2
3/// Output of a `ToolCall` which will be added as a message for the agent to use.
4#[derive(Debug, Clone, PartialEq)]
5#[non_exhaustive]
6pub enum ToolOutput {
7    /// Adds the result of the toolcall to messages
8    Text(String),
9
10    /// Indicates that the toolcall failed, but can be handled by the llm
11    Fail(String),
12    /// Stops an agent
13    Stop,
14}
15
16impl ToolOutput {
17    pub fn content(&self) -> Option<&str> {
18        match self {
19            ToolOutput::Fail(s) | ToolOutput::Text(s) => Some(s),
20            _ => None,
21        }
22    }
23}
24
25impl<T: AsRef<str>> From<T> for ToolOutput {
26    fn from(s: T) -> Self {
27        ToolOutput::Text(s.as_ref().to_string())
28    }
29}
30
31impl std::fmt::Display for ToolOutput {
32    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33        match self {
34            ToolOutput::Text(value) => write!(f, "{value}"),
35            ToolOutput::Fail(value) => write!(f, "Tool call failed: {value}"),
36            ToolOutput::Stop => write!(f, "Stop"),
37        }
38    }
39}
40
41/// A tool call that can be executed by the executor
42#[derive(Clone, Debug, Builder, PartialEq)]
43#[builder(setter(into, strip_option))]
44pub struct ToolCall {
45    id: String,
46    name: String,
47    #[builder(default)]
48    args: Option<String>,
49}
50
51/// Hash is used for finding tool calls that have been retried by agents
52impl std::hash::Hash for &ToolCall {
53    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
54        self.name.hash(state);
55        self.args.hash(state);
56    }
57}
58
59impl std::fmt::Display for ToolCall {
60    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61        write!(
62            f,
63            "{id}#{name} {args}",
64            id = self.id,
65            name = self.name,
66            args = self.args.as_deref().unwrap_or("")
67        )
68    }
69}
70
71impl ToolCall {
72    pub fn builder() -> ToolCallBuilder {
73        ToolCallBuilder::default()
74    }
75
76    pub fn id(&self) -> &str {
77        &self.id
78    }
79
80    pub fn name(&self) -> &str {
81        &self.name
82    }
83
84    pub fn args(&self) -> Option<&str> {
85        self.args.as_deref()
86    }
87}
88
89/// A typed tool specification intended to be usable for multiple LLMs
90///
91/// i.e. the json spec `OpenAI` uses to define their tools
92#[derive(Clone, Debug, Hash, Eq, PartialEq, Default, Builder)]
93pub struct ToolSpec {
94    /// Name of the tool
95    pub name: &'static str,
96    /// Description passed to the LLM for the tool
97    pub description: &'static str,
98
99    #[builder(default)]
100    /// Optional parameters for the tool
101    pub parameters: Vec<ParamSpec>,
102}
103
104impl ToolSpec {
105    pub fn builder() -> ToolSpecBuilder {
106        ToolSpecBuilder::default()
107    }
108}
109
110#[derive(Clone, Debug, Hash, Eq, PartialEq, Default, strum_macros::AsRefStr)]
111#[strum(serialize_all = "camelCase")]
112pub enum ParamType {
113    #[default]
114    String,
115    Number,
116    Boolean,
117    Array,
118    // Enum
119    // Object
120    // anyOf
121}
122
123/// Parameters for tools
124#[derive(Clone, Debug, Hash, Eq, PartialEq, Builder)]
125pub struct ParamSpec {
126    /// Name of the parameter
127    pub name: &'static str,
128    /// Description of the parameter
129    pub description: &'static str,
130    /// Json spec type of the parameter
131    #[builder(default)]
132    pub ty: ParamType,
133    /// Whether the parameter is required
134    ///
135    /// Note that macros will always generate required parameters
136    #[builder(default = true)]
137    pub required: bool,
138}
139
140impl ParamSpec {
141    pub fn builder() -> ParamSpecBuilder {
142        ParamSpecBuilder::default()
143    }
144}