1use async_trait::async_trait;
7use futures_util::{Stream, StreamExt};
8use lc_core::runnables::{LcelError, Runnable, RunnableConfig};
9use serde_json::Value;
10use std::collections::HashMap;
11use std::pin::Pin;
12use std::sync::Arc;
13
14use crate::base::BaseChain;
15
16pub struct ChainRunnable {
25 chain: Arc<dyn BaseChain>,
26}
27
28impl ChainRunnable {
29 pub fn new(chain: Arc<dyn BaseChain>) -> Self {
31 Self { chain }
32 }
33}
34
35#[async_trait]
36impl Runnable<HashMap<String, Value>, HashMap<String, Value>> for ChainRunnable {
37 type Error = LcelError;
38
39 async fn invoke(
40 &self,
41 input: HashMap<String, Value>,
42 config: Option<RunnableConfig>,
43 ) -> Result<HashMap<String, Value>, LcelError> {
44 self.chain
46 .invoke_with_config(input, config)
47 .await
48 .map_err(|e| LcelError::Chain(e.to_string()))
49 }
50
51 async fn stream(
52 &self,
53 input: HashMap<String, Value>,
54 config: Option<RunnableConfig>,
55 ) -> Result<Pin<Box<dyn Stream<Item = Result<HashMap<String, Value>, LcelError>> + Send>>, LcelError> {
56 let chain_stream = self.chain
58 .stream_with_config(input, config)
59 .await
60 .map_err(|e| LcelError::Stream(e.to_string()))?;
61
62 let mapped = chain_stream.map(|result| {
64 result
65 .map(|token| {
66 let mut map = HashMap::new();
67 map.insert("text".to_string(), Value::String(token.token));
68 map
69 })
70 .map_err(|e| LcelError::Stream(e.to_string()))
71 });
72
73 Ok(Box::pin(mapped))
74 }
75
76 }
78
79impl From<crate::base::ChainError> for LcelError {
81 fn from(err: crate::base::ChainError) -> Self {
82 LcelError::Chain(err.to_string())
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89 use lc_core::runnables::Runnable;
90
91 struct TestChain;
92
93 #[async_trait]
94 impl BaseChain for TestChain {
95 fn input_keys(&self) -> Vec<&str> {
96 vec!["input"]
97 }
98
99 fn output_keys(&self) -> Vec<&str> {
100 vec!["output"]
101 }
102
103 async fn invoke(
104 &self,
105 inputs: HashMap<String, Value>,
106 ) -> Result<HashMap<String, Value>, crate::base::ChainError> {
107 let input = inputs
108 .get("input")
109 .and_then(|v| v.as_str())
110 .unwrap_or("");
111 let mut result = HashMap::new();
112 result.insert("output".to_string(), Value::String(format!("echo: {}", input)));
113 Ok(result)
114 }
115 }
116
117 #[tokio::test]
118 async fn chain_runnable_invoke() {
119 let chain = ChainRunnable::new(Arc::new(TestChain));
120 let mut input = HashMap::new();
121 input.insert("input".to_string(), Value::String("hello".to_string()));
122 let result = chain.invoke(input, None).await.unwrap();
123 assert_eq!(result.get("output").unwrap(), &Value::String("echo: hello".to_string()));
124 }
125}