Skip to main content

limit_llm/
lib.rs

1//! # limit-llm
2//!
3//! [![Crates.io](https://img.shields.io/crates/v/limit-llm.svg)](https://crates.io/crates/limit-llm)
4//! [![Docs.rs](https://docs.rs/limit-llm/badge.svg)](https://docs.rs/limit-llm)
5//! [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6//!
7//! **Multi-provider LLM client for Rust with streaming support.**
8//!
9//! Unified API for Anthropic Claude, OpenAI, z.ai, and local LLMs with built-in
10//! token tracking, state persistence, and automatic model handoff.
11//!
12//! ## Features
13//!
14//! - **Multi-provider support**: Anthropic Claude, OpenAI GPT, z.ai GLM, and local LLMs
15//! - **Streaming responses**: Async streaming with `futures::Stream`
16//! - **Token tracking**: SQLite-based usage tracking and cost estimation
17//! - **State persistence**: Serialize/restore conversation state with bincode
18//! - **Model handoff**: Automatic fallback between providers on failure
19//! - **Tool calling**: Full function/tool support for all compatible providers
20//! - **Thinking mode**: Extended reasoning support (Claude, z.ai)
21//!
22//! ## Quick Start
23//!
24//! ```rust,no_run
25//! use limit_llm::{AnthropicClient, Message, Role, LlmProvider};
26//! use futures::StreamExt;
27//!
28//! #[tokio::main]
29//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
30//!     // Create client from environment variable ANTHROPIC_API_KEY
31//!     let client = AnthropicClient::new(
32//!         std::env::var("ANTHROPIC_API_KEY")?,
33//!         None,  // default base URL
34//!         60,    // timeout in seconds
35//!         "claude-sonnet-4-6-20260217",
36//!         4096,  // max tokens
37//!     );
38//!
39//!     let messages = vec![
40//!         Message {
41//!             role: Role::User,
42//!             content: Some("Hello, Claude!".to_string()),
43//!             tool_calls: None,
44//!             tool_call_id: None,
45//!         }
46//!     ];
47//!
48//!     // Stream the response
49//!     let mut stream = client.send(messages, vec![]).await;
50//!     
51//!     while let Some(chunk) = stream.next().await {
52//!         match chunk {
53//!             Ok(limit_llm::ProviderResponseChunk::ContentDelta(text)) => {
54//!                 print!("{}", text);
55//!             }
56//!             Ok(limit_llm::ProviderResponseChunk::Done(usage)) => {
57//!                 println!("\n\nTokens: {} in, {} out",
58//!                     usage.input_tokens, usage.output_tokens);
59//!             }
60//!             Err(e) => eprintln!("Error: {}", e),
61//!             _ => {}
62//!         }
63//!     }
64//!
65//!     Ok(())
66//! }
67//! ```
68//!
69//! ## Providers
70//!
71//! | Provider | Client | Streaming | Tools | Thinking |
72//! |----------|--------|-----------|-------|----------|
73//! | Anthropic Claude | [`AnthropicClient`] | ✓ | ✓ | ✓ |
74//! | OpenAI | [`OpenAiProvider`] | ✓ | ✓ | — |
75//! | z.ai GLM | [`ZaiProvider`] | ✓ | ✓ | ✓ |
76//! | Local/Ollama | [`LocalProvider`] | ✓ | — | — |
77//!
78//! ## Configuration
79//!
80//! ### Environment Variables
81//!
82//! ```bash
83//! ANTHROPIC_API_KEY=your-key      # For Claude
84//! OPENAI_API_KEY=your-key          # For GPT
85//! ZAI_API_KEY=your-key             # For z.ai
86//! ```
87//!
88//! ### Programmatic Configuration
89//!
90//! ```rust,no_run
91//! use limit_llm::{Config, ProviderFactory};
92//!
93//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
94//! // Load from ~/.limit/config.toml
95//! let config = Config::load()?;
96//!
97//! // Create provider from config
98//! let provider = ProviderFactory::create_provider(&config)?;
99//! # Ok(())
100//! # }
101//! ```
102//!
103//! ## Token Tracking
104//!
105//! ```rust,no_run
106//! use limit_llm::TrackingDb;
107//!
108//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
109//! let tracking = TrackingDb::new()?;
110//!
111//! // Track a request
112//! tracking.track_request(
113//!     "claude-sonnet-4-6-20260217",
114//!     100,  // input tokens
115//!     50,   // output tokens
116//!     0.001, // cost in USD
117//!     1500,  // duration in ms
118//! )?;
119//!
120//! // Get statistics for last 7 days
121//! let stats = tracking.get_usage_stats(7)?;
122//! println!("Total cost: ${:.4}", stats.total_cost);
123//! # Ok(())
124//! # }
125//! ```
126//!
127//! ## State Persistence
128//!
129//! ```rust,no_run
130//! use limit_llm::{StatePersistence, Message};
131//!
132//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
133//! let persistence = StatePersistence::new("~/.limit/state/session.bin");
134//!
135//! // Save conversation
136//! let messages: Vec<Message> = vec![];
137//! persistence.save(&messages)?;
138//!
139//! // Restore later
140//! let restored = persistence.load()?;
141//! # Ok(())
142//! # }
143//! ```
144//!
145//! ## Model Handoff
146//!
147//! The `ModelHandoff` type provides token counting and message compaction
148//! for transitioning between models with different context windows:
149//!
150//! ```rust,no_run
151//! use limit_llm::ModelHandoff;
152//!
153//! # fn main() {
154//! let handoff = ModelHandoff::new();
155//!
156//! // Count tokens in a message
157//! let tokens = handoff.count_tokens("Hello, world!");
158//! println!("Token count: {}", tokens);
159//!
160//! // Compact messages to fit a target context window
161//! // let compacted = handoff.handoff_to_model("claude-3-5-sonnet", "claude-3-5-haiku", &messages);
162//! # }
163//! ```
164
165pub mod client;
166pub mod config;
167pub mod error;
168pub mod handoff;
169pub mod local_provider;
170pub mod openai_provider;
171pub mod persistence;
172pub mod provider_factory;
173pub mod providers;
174pub mod tracking;
175pub mod types;
176pub mod zai_provider;
177
178pub use client::AnthropicClient;
179pub use config::{BrowserConfigSection, Config, ProviderConfig};
180pub use error::LlmError;
181pub use handoff::ModelHandoff;
182pub use local_provider::LocalProvider;
183pub use openai_provider::OpenAiProvider;
184pub use persistence::StatePersistence;
185pub use provider_factory::ProviderFactory;
186pub use providers::{LlmProvider, ProviderResponseChunk};
187pub use tracking::TrackingDb;
188pub use types::{FunctionCall, Message, Response, Role, Tool, ToolCall, ToolFunction, Usage};
189pub use zai_provider::{ThinkingConfig, ZaiProvider};