lc_agents/streaming/
tool_call_stream.rs1use std::pin::Pin;
4use std::sync::Arc;
5
6use futures_util::{Stream, StreamExt};
7use tokio::sync::mpsc;
8use tokio_stream::wrappers::ReceiverStream;
9
10use lc_core::language_models::BaseChatModel;
11use lc_core::runnables::RunnableConfig;
12use lc_providers::ProviderError;
13use lc_schema::Message;
14
15use super::state::AgentStreamEvent;
16
17pub struct StreamingFunctionCallingAgent {
23 llm: Arc<dyn BaseChatModel<Error = ProviderError> + Send + Sync>,
24}
25
26impl StreamingFunctionCallingAgent {
27 pub fn new<L>(llm: L) -> Self
32 where
33 L: BaseChatModel + Send + Sync + 'static,
34 L::Error: Into<ProviderError>,
35 {
36 Self {
37 llm: lc_providers::wrap_chat_model(llm),
38 }
39 }
40
41 pub fn from_arc(llm: Arc<dyn BaseChatModel<Error = ProviderError> + Send + Sync>) -> Self {
43 Self { llm }
44 }
45
46 pub async fn invoke_stream(
48 &self,
49 input: String,
50 ) -> Pin<Box<dyn Stream<Item = AgentStreamEvent> + Send>> {
51 self.invoke_stream_with_config(input, None).await
52 }
53
54 pub async fn invoke_stream_with_config(
58 &self,
59 input: String,
60 config: Option<&RunnableConfig>,
61 ) -> Pin<Box<dyn Stream<Item = AgentStreamEvent> + Send>> {
62 let (tx, rx) = mpsc::channel(32);
63 let llm = self.llm.clone();
64 let messages = vec![Message::human(input)];
65 let config = config.cloned();
67
68 tokio::spawn(async move {
69 let mut stream = match llm.stream_chat(messages, config).await {
70 Ok(s) => s,
71 Err(e) => {
72 let _ = tx
73 .send(AgentStreamEvent::Error {
74 message: format!("Stream initialization failed: {}", e),
75 })
76 .await;
77 return;
78 }
79 };
80
81 let mut full = String::new();
82 while let Some(chunk) = stream.next().await {
83 match chunk {
84 Ok(chunk) => {
85 full.push_str(&chunk.text);
86 if tx
87 .send(AgentStreamEvent::Text {
88 content: chunk.text,
89 })
90 .await
91 .is_err()
92 {
93 break;
94 }
95 }
96 Err(e) => {
97 let _ = tx
98 .send(AgentStreamEvent::Error {
99 message: format!("Stream error: {}", e),
100 })
101 .await;
102 break;
103 }
104 }
105 }
106
107 let _ = tx
108 .send(AgentStreamEvent::FinalAnswer { content: full })
109 .await;
110 });
111
112 Box::pin(ReceiverStream::new(rx))
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119 use lc_providers::{OpenAIChat, OpenAIConfig};
120
121 #[test]
122 fn test_new() {
123 let llm = OpenAIChat::new(OpenAIConfig::default());
124 let _agent = StreamingFunctionCallingAgent::new(llm);
125 }
126}