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)]
93#[builder(setter(into))]
94pub struct ToolSpec {
95    /// Name of the tool
96    pub name: String,
97    /// Description passed to the LLM for the tool
98    pub description: String,
99
100    #[builder(default)]
101    /// Optional parameters for the tool
102    pub parameters: Vec<ParamSpec>,
103}
104
105impl ToolSpec {
106    pub fn builder() -> ToolSpecBuilder {
107        ToolSpecBuilder::default()
108    }
109}
110
111#[derive(Clone, Debug, Hash, Eq, PartialEq, Default, strum_macros::AsRefStr)]
112#[strum(serialize_all = "camelCase")]
113pub enum ParamType {
114    #[default]
115    String,
116    Number,
117    Boolean,
118    Array,
119    // Enum
120    // Object
121    // anyOf
122}
123
124/// Parameters for tools
125#[derive(Clone, Debug, Hash, Eq, PartialEq, Builder)]
126#[builder(setter(into))]
127pub struct ParamSpec {
128    /// Name of the parameter
129    pub name: String,
130    /// Description of the parameter
131    pub description: String,
132    /// Json spec type of the parameter
133    #[builder(default)]
134    pub ty: ParamType,
135    /// Whether the parameter is required
136    ///
137    /// Note that macros will always generate required parameters
138    #[builder(default = true)]
139    pub required: bool,
140}
141
142impl ParamSpec {
143    pub fn builder() -> ParamSpecBuilder {
144        ParamSpecBuilder::default()
145    }
146}