llmrix_rust_sdk/client.rs
1use std::{sync::Arc, time::Duration};
2
3use crate::{
4 error::Result,
5 resources::{agents::AgentsResource, chat::ChatResource, conversations::ConversationsResource, cron::CronResource},
6 transport::Transport,
7};
8
9/// Main entry point for the Llmrix Rust SDK.
10///
11/// `LlmrixClient` is cheap to clone — all instances share the same underlying
12/// connection pool via `Arc<Transport>`.
13///
14/// # Example
15/// ```rust,no_run
16/// # use llmrix_rust_sdk::{LlmrixClient, model::ConversationCreateRequest};
17/// # #[tokio::main] async fn main() -> llmrix_rust_sdk::error::Result<()> {
18/// let client = LlmrixClient::builder()
19/// .base_url("http://localhost:8899")
20/// .api_key("sk-xxx")
21/// .build()?;
22///
23/// let conv = client.conversations()
24/// .create(ConversationCreateRequest { title: "My chat".into(), agent_id: None })
25/// .await?;
26///
27/// client.chat(&conv.id).send("Hello!", |event| {
28/// use llmrix_rust_sdk::streaming::event::StreamEvent;
29/// if let StreamEvent::MessageChunk(e) = event {
30/// print!("{}", e.content);
31/// }
32/// Ok(())
33/// }).await?;
34/// # Ok(()) }
35/// ```
36#[derive(Clone)]
37pub struct LlmrixClient {
38 transport: Arc<Transport>,
39}
40
41impl LlmrixClient {
42 /// Returns a builder for configuring and constructing a [`LlmrixClient`].
43 pub fn builder() -> ClientBuilder {
44 ClientBuilder::default()
45 }
46
47 /// Returns the resource for managing conversations and message history.
48 pub fn conversations(&self) -> ConversationsResource {
49 ConversationsResource { t: Arc::clone(&self.transport) }
50 }
51
52 /// Returns the resource for managing scheduled cron tasks.
53 pub fn cron(&self) -> CronResource {
54 CronResource { t: Arc::clone(&self.transport) }
55 }
56
57 /// Returns the resource for managing agents and their mates.
58 /// Returns HTTP 503 in native/standalone server mode.
59 pub fn agents(&self) -> AgentsResource {
60 AgentsResource { t: Arc::clone(&self.transport) }
61 }
62
63 /// Returns a [`ChatResource`] scoped to the given conversation ID.
64 pub fn chat(&self, conv_id: impl Into<String>) -> ChatResource {
65 ChatResource { t: Arc::clone(&self.transport), conv_id: conv_id.into() }
66 }
67}
68
69// ---------------------------------------------------------------------------
70// Builder
71// ---------------------------------------------------------------------------
72
73/// Builder for [`LlmrixClient`].
74#[derive(Default)]
75pub struct ClientBuilder {
76 base_url: Option<String>,
77 api_key: String,
78 timeout: Option<Duration>,
79}
80
81impl ClientBuilder {
82 /// Base URL of the Llmrix server, e.g. `"http://localhost:8899"`. **Required.**
83 pub fn base_url(mut self, url: impl Into<String>) -> Self {
84 self.base_url = Some(url.into().trim_end_matches('/').to_string());
85 self
86 }
87
88 /// API key sent in the `Authorization: Bearer` header.
89 /// Omit if the server has no auth configured.
90 pub fn api_key(mut self, key: impl Into<String>) -> Self {
91 self.api_key = key.into();
92 self
93 }
94
95 /// HTTP request timeout for non-streaming requests (default: 60 s).
96 /// SSE streaming calls use no overall timeout.
97 pub fn timeout(mut self, d: Duration) -> Self {
98 self.timeout = Some(d);
99 self
100 }
101
102 /// Construct the [`LlmrixClient`].
103 ///
104 /// # Errors
105 /// Returns an error if `base_url` was not set or if the HTTP client could
106 /// not be built (e.g. invalid TLS configuration).
107 pub fn build(self) -> Result<LlmrixClient> {
108 let base_url = self.base_url
109 .expect("LlmrixClient: base_url is required — call .base_url(\"http://...\")");
110 let timeout = self.timeout.unwrap_or(Duration::from_secs(60));
111 let transport = Transport::new(base_url, self.api_key, timeout)?;
112 Ok(LlmrixClient { transport: Arc::new(transport) })
113 }
114}