Official Rust SDK for llmrix — AI Agent Platform.
- Rust 1.75+ (MSRV)
- Async/await with
tokioruntime - SSE streaming via
reqwest+futures-util - Fully typed with
serdeserialization thiserror-based error hierarchy
Add to your Cargo.toml:
[dependencies]
llmrix-rust-sdk = "1.0"
tokio = { version = "1", features = ["full"] }use llmrix_sdk::{
LlmrixClient,
model::ConversationCreateRequest,
streaming::event::StreamEvent,
};
#[tokio::main]
async fn main() -> llmrix_sdk::error::Result<()> {
// 1. Build the client (cheap to clone — shares the connection pool)
let client = LlmrixClient::builder()
.base_url("https://www.llmrix.com")
.api_key("sk-xxx")
.build()?;
// 2. Create a conversation
let conv = client
.conversations()
.create(ConversationCreateRequest {
title: "My Chat".into(),
agent_id: None,
})
.await?;
// 3. Stream a chat turn
client
.chat(&conv.id)
.send("Hello, llmrix!", |event| {
if let StreamEvent::MessageChunk(e) = event {
print!("{}", e.content);
}
Ok(())
})
.await?;
Ok(())
}LlmrixClient::builder()
.base_url("https://www.llmrix.com") // required
.api_key("sk-xxx") // optional
.timeout(std::time::Duration::from_secs(60)) // optional, default 60 s
.build()?LlmrixClient is Clone and cheap to clone — the inner reqwest::Client
shares its connection pool across all clones.
Obtained via client.conversations().
| Method | Returns | Description |
|---|---|---|
create(req).await |
Result<Conversation> |
Create a new conversation |
list(last_id, size).await |
Result<PageResult<Conversation>> |
Cursor-paginated list |
get(id).await |
Result<Conversation> |
Fetch a single conversation |
update(id, req).await |
Result<Conversation> |
Update title / agent |
delete(id).await |
Result<()> |
Permanently delete |
messages(id, last_id, size).await |
Result<PageResult<Message>> |
Paginated message history |
Cursor pagination:
let mut page = client.conversations().list(0, 20).await?;
while page.has_more {
let last = page.items.last().unwrap();
page = client.conversations().list(last.seq, 20).await?;
}Obtained via client.chat(conv_id).
| Method | Returns | Description |
|---|---|---|
send(message, handler).await |
Result<()> |
Stream a plain-text message |
send_request(req, handler).await |
Result<()> |
Stream a full ChatRequest |
stop().await |
Result<()> |
Cancel the current run |
decide(decisions).await |
Result<()> |
Submit HITL decisions |
type StreamHandler = impl FnMut(StreamEvent) -> Result<()>;Returning Err(...) from the handler aborts the stream.
use llmrix_sdk::streaming::event::StreamEvent;
client.chat(&conv.id).send("Search for cats", |event| {
match event {
StreamEvent::MessageChunk(e) => print!("{}", e.content),
StreamEvent::ToolStart(e) => println!("\n[tool] {}", e.name),
StreamEvent::HitlInterrupt(e) => {
// submit decision...
}
StreamEvent::RunEnd(_) => {}
StreamEvent::Error(e) => eprintln!("error: {}", e.message),
_ => {}
}
Ok(())
}).await?;| Variant | Channel | Description |
|---|---|---|
RunStart |
lifecycle |
Agent run started |
RunEnd |
lifecycle |
Agent run completed |
MessageChunk |
messages |
Incremental text chunk |
ToolStart |
tools |
Tool invocation started |
ToolEnd |
tools |
Tool invocation finished |
SubagentStart |
tools |
Sub-agent spawned |
SubagentEnd |
tools |
Sub-agent finished |
HitlInterrupt |
hitl |
Human approval required |
Error |
error |
Run failed with error |
Cancelled |
error |
Run was cancelled |
Heartbeat |
heartbeat |
Keep-alive (silently dropped) |
use llmrix_sdk::error::{LlmrixError, Result};
match client.conversations().get("bad-id").await {
Err(LlmrixError::Api { status, body }) => {
eprintln!("HTTP {}: {}", status, body);
}
Err(LlmrixError::Auth { status, body }) => {
eprintln!("Auth failed ({}): {}", status, body);
}
Err(e) => eprintln!("SDK error: {}", e),
Ok(conv) => println!("Got: {}", conv.id),
}| Variant | When |
|---|---|
LlmrixError::Api |
Non-2xx HTTP response; has status and body |
LlmrixError::Auth |
HTTP 401 / 403 |
LlmrixError::Http |
Network-level reqwest error |
LlmrixError::Sse |
Unrecoverable SSE parse error |
use llmrix_sdk::model::HitlDecision;
let chat = client.chat(&conv.id);
chat.send("Delete old backups", |event| {
if let StreamEvent::HitlInterrupt(e) = event {
println!("Approve '{}'? (y/n)", e.action_name);
let mut ans = String::new();
std::io::stdin().read_line(&mut ans).unwrap();
let decision = if ans.trim() == "y" {
HitlDecision::approve()
} else {
HitlDecision::reject("user declined")
};
// Note: use tokio::task::block_in_place or restructure as needed
// for true async decide
println!("Decision recorded: {:?}", decision);
}
Ok(())
}).await?;async fn run_to_completion(
client: &LlmrixClient,
conv_id: &str,
message: &str,
) -> Result<String> {
let mut output = String::new();
client.chat(conv_id).send(message, |event| {
if let StreamEvent::MessageChunk(e) = event {
output.push_str(&e.content);
}
Ok(())
}).await?;
Ok(output)
}git clone https://github.com/llmrix/llmrix-rust-sdk.git
cd llmrix-rust-sdk
cargo build
cargo testGenerate documentation:
cargo doc --openContributions are welcome! Please read CONTRIBUTING.md first.
Apache License 2.0 — see the LICENSE file.