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}