Skip to main content

llmrix_rust_sdk/resources/
chat.rs

1use std::sync::Arc;
2use crate::{
3    error::{LlmrixError, Result},
4    model::{ChatRequest, HitlDecideRequest, HitlDecision},
5    streaming::event::StreamEvent,
6    transport::*,
7};
8
9/// Streaming chat, stop, and HITL-decision operations scoped to one conversation.
10/// Obtain via [`LlmrixClient::chat`].
11pub struct ChatResource {
12    pub(crate) t:       Arc<Transport>,
13    pub(crate) conv_id: String,
14}
15
16impl ChatResource {
17    /// Send a plain-text message and stream the agent's response.
18    ///
19    /// `handler` is called synchronously for each received [`StreamEvent`].
20    /// Return `Err` from the handler to abort streaming early.
21    ///
22    /// ```rust,no_run
23    /// # use llmrix_rust_sdk::{LlmrixClient, streaming::event::StreamEvent};
24    /// # #[tokio::main] async fn main() -> llmrix_rust_sdk::error::Result<()> {
25    /// # let client = LlmrixClient::builder().base_url("http://localhost").build().unwrap();
26    /// # let conv_id = "test-id";
27    /// client.chat(conv_id).send("Hello!", |event| {
28    ///     if let StreamEvent::MessageChunk(e) = event {
29    ///         print!("{}", e.content);
30    ///     }
31    ///     Ok(())
32    /// }).await?;
33    /// # Ok(()) }
34    /// ```
35    pub async fn send<F>(&self, message: &str, handler: F) -> Result<()>
36    where
37        F: FnMut(&StreamEvent) -> Result<()>,
38    {
39        self.send_request(ChatRequest { message: message.to_string(), ..Default::default() }, handler)
40            .await
41    }
42
43    /// Send a fully-specified [`ChatRequest`] and stream the response.
44    /// Use this overload to supply `agent_id`, `metadata`, or HITL decisions inline.
45    pub async fn send_request<F>(&self, req: ChatRequest, handler: F) -> Result<()>
46    where
47        F: FnMut(&StreamEvent) -> Result<()>,
48    {
49        self.t.stream(&path_chat(&self.conv_id), &req, handler).await
50    }
51
52    /// Request the server to cancel the currently running chat turn.
53    /// The in-flight `send` call will receive a `Cancelled` event before the stream closes.
54    pub async fn stop(&self) -> Result<()> {
55        self.t.post_no_body(&path_chat_stop(&self.conv_id)).await
56    }
57
58    /// Submit HITL decisions to resume a paused agent run.
59    /// Call this after receiving a `HitlInterrupt` event.
60    pub async fn decide(&self, decisions: Vec<HitlDecision>) -> Result<()> {
61        if decisions.is_empty() {
62            return Err(LlmrixError::Other("decisions must not be empty".into()));
63        }
64        self.t
65            .post_void(&path_chat_decide(&self.conv_id), &HitlDecideRequest { decisions })
66            .await
67    }
68}