llm_chain/
parameters.rs

1//! Parameters are used to pass data steps of the chain. This module implements them.
2//!
3//! Parameters are used to pass data between steps of the chain. They are used to fill in the prompt template, and are also filled in by the output of the previous step. Parameters have a special key, `text`, which is used as a default key for simple use cases.
4
5use std::{
6    collections::{BTreeMap, HashMap},
7    fmt::Debug,
8};
9
10type Map = BTreeMap<String, Box<dyn ParamFull>>;
11
12/// Parameters define the parameters sent into each step. The parameters are used to fill in the prompt template, and are also filled in by the output of the previous step. Parameters have a special key, `text`, which is used as a default key for simple use cases.
13///
14/// Parameters also implement a few convenience conversion traits to make it easier to work with them.
15///
16/// # Examples
17///
18/// **Creating a default parameter from a string**
19/// ```
20/// use llm_chain::Parameters;
21/// let p: Parameters = "Hello world!".into();
22/// assert_eq!(p.get("text").unwrap().as_str(), "Hello world!");
23/// ```
24/// **Creating a list of parameters from a list of pairs**
25/// ```
26/// use llm_chain::Parameters;
27/// let p: Parameters = vec![("text", "Hello world!"), ("name", "John Doe")].into();
28/// assert_eq!(p.get("text").unwrap().as_str(), "Hello world!");
29/// assert_eq!(p.get("name").unwrap().as_str(), "John Doe");
30/// ```
31#[derive(Default, Debug)]
32pub struct Parameters {
33    map: Map,
34}
35
36impl Clone for Parameters {
37    fn clone(&self) -> Self {
38        let mut map = Map::new();
39        for (key, value) in self.map.iter() {
40            map.insert(key.clone(), value.boxed_clone());
41        }
42        Self { map }
43    }
44}
45
46impl PartialEq for Parameters {
47    fn eq(&self, other: &Self) -> bool {
48        self.map.keys().len() == other.map.keys().len()
49            && self.map.iter().all(|(k, v)| {
50                if let Some(other_v) = other.map.get(k) {
51                    v.get() == other_v.get()
52                } else {
53                    false
54                }
55            })
56    }
57}
58
59pub trait Param: Send + Sync {
60    fn get(&self) -> String;
61}
62
63/// This trait is used to implement a dynamic parameter this shouldn't be used but exists only for internal purposes.
64#[doc(hidden)]
65pub trait ParamFull: Param + Debug + Send + Sync {
66    #[doc(hidden)]
67    fn boxed_clone(&self) -> Box<dyn ParamFull + Send>;
68}
69
70impl<T: Param + Debug + Clone + 'static> ParamFull for T {
71    #[doc(hidden)]
72    fn boxed_clone(&self) -> Box<dyn ParamFull + Send> {
73        Box::new(self.clone())
74    }
75}
76#[derive(Debug, Clone)]
77struct StringParam {
78    value: String,
79}
80
81impl StringParam {
82    fn new(value: String) -> Self {
83        Self { value }
84    }
85}
86
87impl Param for StringParam {
88    fn get(&self) -> String {
89        self.value.clone()
90    }
91}
92
93const TEXT_KEY: &str = "text";
94
95impl Parameters {
96    /// Creates a new empty set of parameters.
97    pub fn new() -> Parameters {
98        Default::default()
99    }
100    /// Creates a new set of parameters with a single key, `text`, set to the given value.
101    pub fn new_with_text<T: Into<String>>(text: T) -> Parameters {
102        let mut map = Map::new();
103        map.insert(
104            TEXT_KEY.to_string(),
105            Box::new(StringParam::new(text.into())),
106        );
107        Parameters { map }
108    }
109    /// Copies the parameters and adds a new key-value pair.
110    pub fn with<K: Into<String>, V: Into<String>>(&self, key: K, value: V) -> Parameters {
111        let mut copy = self.clone();
112        copy.map
113            .insert(key.into(), Box::new(StringParam::new(value.into())));
114        copy
115    }
116
117    /// Copies the parameters and adds a new key-value pair pair, where the value is a dynamic parameter.
118    pub fn with_dynamic<K: Into<String>, V: ParamFull>(&self, key: K, value: V) -> Parameters {
119        let mut copy = self.clone();
120        copy.map.insert(key.into(), value.boxed_clone());
121        copy
122    }
123
124    /// Copies the parameters and adds a new key-value pair with the key `text`, which is the default key.
125    pub fn with_text<K: Into<String>>(&self, text: K) -> Parameters {
126        self.with(TEXT_KEY, text)
127    }
128
129    /// Combines two sets of parameters, returning a new set of parameters with all the keys from both sets.
130    pub fn combine(&self, other: &Parameters) -> Parameters {
131        let mut copy = self.clone();
132        for (key, value) in other.map.iter() {
133            copy.map.insert(key.clone(), value.boxed_clone());
134        }
135        copy
136    }
137    /// Returns the value of the given key, or `None` if the key does not exist.
138    pub fn get(&self, key: &str) -> Option<String> {
139        self.map.get(key).map(|param| param.get())
140    }
141
142    pub fn get_text(&self) -> Option<String> {
143        self.get(TEXT_KEY)
144    }
145
146    pub(crate) fn to_tera(&self) -> tera::Context {
147        let mut context = tera::Context::new();
148        for (key, value) in self.map.iter() {
149            context.insert(key, &value.get());
150        }
151        context
152    }
153
154    fn from_seq<K, V, M>(m: M) -> Self
155    where
156        K: Into<String>,
157        V: Into<String>,
158        M: IntoIterator<Item = (K, V)>,
159    {
160        let mut map = Map::new();
161        for (k, v) in m.into_iter() {
162            map.insert(k.into(), Box::new(StringParam::new(v.into())));
163        }
164        Parameters { map }
165    }
166}
167
168impl From<String> for Parameters {
169    fn from(text: String) -> Self {
170        Parameters::new_with_text(text)
171    }
172}
173
174impl From<&str> for Parameters {
175    fn from(text: &str) -> Self {
176        Parameters::new_with_text(text)
177    }
178}
179
180impl From<HashMap<String, String>> for Parameters {
181    fn from(map: HashMap<String, String>) -> Self {
182        Parameters::from_seq(map.into_iter())
183    }
184}
185
186impl From<BTreeMap<String, String>> for Parameters {
187    fn from(map: BTreeMap<String, String>) -> Self {
188        Parameters::from_seq(map.into_iter())
189    }
190}
191
192impl From<Vec<(String, String)>> for Parameters {
193    fn from(data: Vec<(String, String)>) -> Self {
194        Parameters::from_seq(data.into_iter())
195    }
196}
197
198impl From<Vec<(&str, &str)>> for Parameters {
199    fn from(data: Vec<(&str, &str)>) -> Self {
200        Parameters::from_seq(data)
201    }
202}
203
204/// A macro that creates a new `Parameters` instance with the provided key-value pairs.
205///
206/// This macro makes it easy to create a new `Parameters` instance without having to call the constructor functions directly. It supports different input formats for creating `Parameters` instances with different key-value pairs.
207///
208/// # Usage
209///
210/// ```
211/// # use llm_chain::parameters;
212/// parameters!(); // Creates an empty Parameters instance.
213/// ```
214///
215/// # Examples
216///
217/// ```
218/// # use llm_chain::parameters;
219/// // Create an empty Parameters instance.
220/// let params = parameters!();
221///
222/// // Create a Parameters instance with the "text" key set to "some text".
223/// let params_with_text = parameters!("some text");
224///
225/// // Create a Parameters instance with multiple key-value pairs.
226/// let params_with_multiple = parameters! {
227///     "key1" => "val1",
228///     "key2" => "val2"
229/// };
230/// ```
231///
232/// # Parameters
233///
234/// - `()`: Creates an empty `Parameters` instance.
235/// - `"some text"`: Creates a `Parameters` instance with the "text" key set to "some text".
236/// - `{"key1" => "val1", "key2" => "val2"}`: Creates a `Parameters` instance with the specified key-value pairs.
237#[macro_export]
238macro_rules! parameters {
239    () => {
240        $crate::Parameters::new()
241    };
242    ($text:expr) => {
243        llm_chain::Parameters::new_with_text($text)
244    };
245    ($($key:expr => $value:expr),+$(,)?) => {{
246        let mut params = $crate::Parameters::new();
247        $(
248            params = params.with($key, $value);
249        )+
250        params
251    }};
252}