swiftide_core/chat_completion/
tools.rs

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