The Rust crate is the native implementation of llms-sdk. It provides the full feature set and powers the TypeScript and Python bindings.
Installation
Add the crate to your Cargo.toml:
[dependencies]
llms-sdk = "0.2"Enable optional features as needed:
[dependencies]
llms-sdk = { version = "0.2", features = ["cli"] }Quick start
use llms_sdk::{ApiType, LLM, LLMRequest, Message, MessagePart, MessageRole, RetryPolicy, TextPart};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let request = LLMRequest {
api_type: ApiType::OpenAI,
base_url: None,
api_key: std::env::var("OPENAI_API_KEY")?,
model: "gpt-5.4-mini".to_string(),
messages: vec![Message {
role: MessageRole::User,
content: vec![MessagePart::Text(TextPart::new("Hello!"))],
}],
max_output_tokens: Some(256),
temperature: Some(0.7),
top_p: None,
reasoning_effort: None,
prompt_cache_ttl: None,
stream: false,
output_format: None,
tools: None,
tool_choice: None,
parallel_tool_calls: false,
};
let llm = LLM::new(RetryPolicy::default());
let response = llm.respond(request).await?;
println!("{:?}", response);
Ok(())
}Building requests
Use LLMRequest::builder() to construct requests fluently:
use llms_sdk::{ApiType, LLMRequest, Message, MessagePart, MessageRole, TextPart};
let request = LLMRequest::builder()
.api_type(ApiType::Anthropic)
.api_key(std::env::var("ANTHROPIC_API_KEY").unwrap())
.model("claude-5-sonnet".to_string())
.messages(vec![Message {
role: MessageRole::User,
content: vec![MessagePart::Text(TextPart::new("Hi!"))],
}])
.max_output_tokens(256)
.build();Multimodal input
Image
use llms_sdk::{ImagePart, Message, MessagePart, MessageRole, TextPart};
let image = ImagePart::try_from_file("files/cat.jpeg".to_string())?;
let message = Message {
role: MessageRole::User,
content: vec![
MessagePart::Text(TextPart::new("Describe this image.")),
MessagePart::Image(image),
],
};Audio (OpenAI only)
use llms_sdk::{AudioPart, Message, MessagePart, MessageRole, TextPart};
let audio = AudioPart::try_from_file("files/audio.wav".to_string())?;
let message = Message {
role: MessageRole::User,
content: vec![
MessagePart::Text(TextPart::new("Describe this audio.")),
MessagePart::Audio(audio),
],
};Document (Anthropic only)
use llms_sdk::{DocumentPart, Message, MessagePart, MessageRole, TextPart};
let doc = DocumentPart::try_from_pdf_file("files/file.pdf".to_string())?;
let message = Message {
role: MessageRole::User,
content: vec![
MessagePart::Text(TextPart::new("Summarize this document.")),
MessagePart::Document(doc),
],
};Structured output
use llms_sdk::{LLMRequest, OutputFormat};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, JsonSchema)]
struct Capital {
country: String,
capital: String,
}
let request = LLMRequest {
output_format: Some(OutputFormat {
name: "capital".to_string(),
description: "Country capital".to_string(),
schema: schemars::schema_for!(Capital).into(),
}),
..request
};Tool use
use llms_sdk::{Tool, ToolChoice};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, JsonSchema)]
struct WeatherArgs {
city: String,
}
let tool = Tool::new::<WeatherArgs>("get_weather", "Return weather for a city.");
let request = LLMRequest {
tools: Some(vec![tool]),
tool_choice: Some(ToolChoice::Auto),
..request
};Streaming
Set stream: true and consume the returned stream:
use futures_util::StreamExt;
use llms_sdk::LLMStreamingResponse;
let request = LLMRequest { stream: true, ..request };
let mut stream = llm.stream_response(request).await?;
while let Some(item) = stream.next().await {
match item? {
LLMStreamingResponse::Delta(d) => println!("{}", d.delta.unwrap_or_default()),
LLMStreamingResponse::Complete(c) => println!("done: {:?}", c),
_ => {}
}
}CLI
Install and run the CLI with the cli feature enabled:
cargo install llms-sdk --features cli
llms --help