lc_core/runnables/
config.rs1use serde_json::Value;
5use std::collections::HashMap;
6use std::sync::Arc;
7use uuid::Uuid;
8
9use lc_callbacks::CallbackManager;
10
11use super::cancellation::CancellationToken;
12
13#[derive(Debug, Clone, Default)]
15pub struct RunnableConfig {
16 pub tags: Vec<String>,
18
19 pub metadata: HashMap<String, Value>,
21
22 pub max_concurrency: Option<usize>,
24
25 pub run_id: Option<Uuid>,
27
28 pub run_name: Option<String>,
30
31 pub callbacks: Option<Arc<CallbackManager>>,
33
34 pub cancellation_token: Option<CancellationToken>,
36
37 pub temperature: Option<f32>,
43
44 pub max_tokens: Option<usize>,
49
50 pub configurable: HashMap<String, Value>,
57}
58
59impl RunnableConfig {
60 pub fn new() -> Self {
62 Self::default()
63 }
64
65 pub fn with_tag(mut self, tag: impl Into<String>) -> Self {
67 self.tags.push(tag.into());
68 self
69 }
70
71 pub fn with_metadata(mut self, key: impl Into<String>, value: Value) -> Self {
73 self.metadata.insert(key.into(), value);
74 self
75 }
76
77 pub fn with_max_concurrency(mut self, max: usize) -> Self {
79 self.max_concurrency = Some(max);
80 self
81 }
82
83 pub fn with_run_id(mut self, id: Uuid) -> Self {
85 self.run_id = Some(id);
86 self
87 }
88
89 pub fn with_run_name(mut self, name: impl Into<String>) -> Self {
91 self.run_name = Some(name.into());
92 self
93 }
94
95 pub fn with_callbacks(mut self, callbacks: Arc<CallbackManager>) -> Self {
97 self.callbacks = Some(callbacks);
98 self
99 }
100
101 pub fn with_cancellation_token(mut self, token: CancellationToken) -> Self {
103 self.cancellation_token = Some(token);
104 self
105 }
106
107 pub fn with_temperature(mut self, temperature: f32) -> Self {
109 self.temperature = Some(temperature);
110 self
111 }
112
113 pub fn with_max_tokens(mut self, max_tokens: usize) -> Self {
115 self.max_tokens = Some(max_tokens);
116 self
117 }
118
119 pub fn with_configurable(mut self, key: impl Into<String>, value: Value) -> Self {
129 self.configurable.insert(key.into(), value);
130 self
131 }
132
133 pub fn configurable_value(&self, key: &str) -> Option<&Value> {
135 self.configurable.get(key)
136 }
137
138 pub fn is_cancelled(&self) -> bool {
140 self.cancellation_token
141 .as_ref()
142 .is_some_and(|t| t.is_cancelled())
143 }
144
145 pub fn merge(mut self, other: RunnableConfig) -> Self {
147 for tag in other.tags {
149 if !self.tags.iter().any(|existing| existing == &tag) {
150 self.tags.push(tag);
151 }
152 }
153
154 self.metadata.extend(other.metadata);
156
157 self.configurable.extend(other.configurable);
159
160 if other.max_concurrency.is_some() {
162 self.max_concurrency = other.max_concurrency;
163 }
164 if other.run_id.is_some() {
165 self.run_id = other.run_id;
166 }
167 if other.run_name.is_some() {
168 self.run_name = other.run_name;
169 }
170 if other.cancellation_token.is_some() {
171 self.cancellation_token = other.cancellation_token;
172 }
173 if other.temperature.is_some() {
174 self.temperature = other.temperature;
175 }
176 if other.max_tokens.is_some() {
177 self.max_tokens = other.max_tokens;
178 }
179
180 if let (Some(self_cb), Some(other_cb)) = (&self.callbacks, &other.callbacks) {
184 self.callbacks = Some(Arc::new(self_cb.merge_with(other_cb)));
185 } else if other.callbacks.is_some() {
186 self.callbacks = other.callbacks;
187 }
188
189 self
190 }
191}
192
193#[cfg(test)]
194mod tests {
195 use super::*;
196 use serde_json::json;
197
198 #[test]
199 fn configurable_roundtrip() {
200 let cfg = RunnableConfig::new().with_configurable("session_id", json!("s1"));
201 assert_eq!(cfg.configurable_value("session_id"), Some(&json!("s1")));
202 assert_eq!(cfg.configurable_value("missing"), None);
203 }
204
205 #[test]
206 fn configurable_merge_overrides() {
207 let base = RunnableConfig::new().with_configurable("which", json!("a"));
208 let other = RunnableConfig::new().with_configurable("which", json!("b"));
209 let merged = base.merge(other);
210 assert_eq!(merged.configurable_value("which"), Some(&json!("b")));
211 assert_eq!(merged.configurable_value("none"), None);
213 }
214}