cloudllm/lib.rs
1//! # CloudLLM
2//!
3//! CloudLLM is a batteries-included Rust toolkit for orchestrating intelligent agents that
4//! converse with remote Large Language Models and execute structured actions through tools.
5//!
6//! The crate provides carefully layered abstractions for:
7//!
8//! * **Agents with Tools**: [`Agent`] abstractions that connect to LLMs and execute actions
9//! through a flexible, multi-protocol tool system via [`tool_protocol::ToolRegistry`]
10//! * **Tool Routing**: Local Rust functions, remote MCP servers, Memory persistence, or custom
11//! protocols all accessible through a unified interface
12//! * **Server Deployment**: `MCPServerBuilder` (available on `mcp-server` feature) for easily deploying tool servers
13//! with HTTP support, authentication, and IP filtering
14//! * **Stateful Conversations**: [`LLMSession`] for maintaining rolling conversation history
15//! with context trimming and token accounting
16//! * **Multi-Agent Orchestration**: [`orchestration`] module for coordinating discussions across
17//! multiple agents with Parallel, RoundRobin, Moderated, Hierarchical, Debate, Ralph, or
18//! AnthropicAgentTeams patterns
19//! * **Provider Flexibility**: [`ClientWrapper`] trait implemented for OpenAI, Anthropic Claude,
20//! Google Gemini, xAI Grok, OpenRouter (any of 300+ upstream models), and custom OpenAI-compatible endpoints
21//!
22//! The crate aims to provide documentation-quality examples for every public API. These
23//! examples are kept up to date and are written to compile under `cargo test --doc`.
24//!
25//! ## Core Concepts
26//!
27//! ### LLMSession: Stateful Conversations (The Foundation)
28//!
29//! [`LLMSession`] is the foundational abstraction—it wraps a client to maintain a rolling
30//! conversation history with automatic context trimming and token accounting. Perfect for
31//! simple use cases where you need persistent conversation state:
32//!
33//! ```rust,no_run
34//! use std::sync::Arc;
35//! use cloudllm::{LLMSession, Role};
36//! use cloudllm::clients::openai::{OpenAIClient, Model};
37//!
38//! #[tokio::main]
39//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
40//! let client = Arc::new(OpenAIClient::new_with_model_enum(
41//! &std::env::var("OPEN_AI_SECRET")?,
42//! Model::GPT41Mini
43//! ));
44//!
45//! let mut session = LLMSession::new(client, "You are helpful.".into(), 8_192);
46//!
47//! let reply = session
48//! .send_message(Role::User, "Hello, how are you?".into(), None)
49//! .await?;
50//!
51//! println!("Assistant: {}", reply.content);
52//! println!("Tokens used: {:?}", session.token_usage());
53//! Ok(())
54//! }
55//! ```
56//!
57//! ### Agents: The Heart of CloudLLM
58//!
59//! [`Agent`] extends [`LLMSession`] by adding identity, expertise, and optional tools. Agents are
60//! the primary way to build sophisticated LLM interactions—they maintain personality and can
61//! execute actions through tools:
62//!
63//! ```rust,no_run
64//! use std::sync::Arc;
65//! use cloudllm::Agent;
66//! use cloudllm::clients::openai::{OpenAIClient, Model};
67//! use cloudllm::tool_protocol::ToolRegistry;
68//!
69//! #[tokio::main]
70//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
71//! let client = Arc::new(OpenAIClient::new_with_model_enum(
72//! &std::env::var("OPEN_AI_SECRET")?,
73//! Model::GPT41Mini
74//! ));
75//!
76//! let agent = Agent::new("assistant", "My AI Assistant", client)
77//! .with_expertise("Problem solving")
78//! .with_personality("Friendly and analytical");
79//!
80//! // Agent is now ready to execute actions with tools!
81//! Ok(())
82//! }
83//! ```
84//!
85//! ### Tool Registry: Multi-Protocol Tool Access
86//!
87//! Agents access tools through the [`tool_protocol::ToolRegistry`], which supports **multiple
88//! simultaneous protocols**. Register tools from different sources—local Rust functions, remote
89//! MCP servers, persistent Memory, custom implementations—and agents access them transparently:
90//!
91//! - **Local Tools**: Rust closures and async functions via [`tool_protocols::CustomToolProtocol`]
92//! - **Remote Tools**: HTTP-based MCP servers via [`tool_protocols::McpClientProtocol`]
93//! - **Persistent Memory**: Key-value storage with TTL via [`tool_protocols::MemoryProtocol`]
94//! - **Custom Protocols**: Implement [`tool_protocol::ToolProtocol`] for any system
95//!
96//! ```rust,no_run
97//! use std::sync::Arc;
98//! use cloudllm::tool_protocol::ToolRegistry;
99//! use cloudllm::tool_protocols::CustomToolProtocol;
100//!
101//! # #[tokio::main]
102//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
103//! let mut registry = ToolRegistry::empty();
104//!
105//! // Add local tools
106//! let local = Arc::new(CustomToolProtocol::new());
107//! let _ = registry.add_protocol("local", local).await;
108//!
109//! // Add remote MCP servers
110//! use cloudllm::tool_protocols::McpClientProtocol;
111//! let mcp_server = Arc::new(McpClientProtocol::new("http://localhost:8080".to_string()));
112//! let _ = registry.add_protocol("remote", mcp_server).await;
113//!
114//! // Agent uses tools from both sources transparently!
115//! # Ok(())
116//! # }
117//! ```
118//!
119//! ### Provider Abstraction
120//!
121//! Each cloud provider (OpenAI, Anthropic/Claude, Google Gemini, xAI Grok, OpenRouter, and
122//! custom OpenAI-compatible endpoints) is exposed as a `ClientWrapper` implementation.
123//! All wrappers share the same ergonomics for synchronous calls, streaming, and token
124//! accounting.
125//!
126//! ### Multi-Agent Orchestration
127//!
128//! The [`orchestration`] module orchestrates conversations between multiple agents across a variety
129//! of collaboration patterns:
130//! - **Parallel**: All agents respond simultaneously with aggregated results
131//! - **RoundRobin**: Agents take sequential turns building on previous responses
132//! - **Moderated**: Agents propose ideas, moderator synthesizes the answer
133//! - **Hierarchical**: Lead agent coordinates, specialists handle specific aspects
134//! - **Debate**: Agents discuss and challenge until convergence
135//! - **Ralph**: Autonomous iterative loop working through a PRD task list
136//! - **AnthropicAgentTeams**: Decentralized task-based coordination where agents autonomously
137//! discover, claim, and complete tasks from a shared pool with no central orchestrator
138//!
139//! ### Deploying Tool Servers with MCPServerBuilder
140//!
141//! Create standalone MCP servers that expose tools over HTTP with a simple builder API.
142//! Perfect for microservices or sharing tool capabilities across the network:
143//!
144//! For a complete MCP server example with HTTP support, see the `examples/mcp_server_all_tools.rs`
145//! example which demonstrates deploying all built-in tools via HTTP with authentication and IP filtering.
146//!
147//! MCPServerBuilder is available on the `mcp-server` feature (requires `axum` and `tower`).
148//!
149//! ### Creating Tools: Simple to Advanced
150//!
151//! Tools are the actions agents can take. CloudLLM supports multiple ways to create them:
152//!
153//! **Simple Approach: Rust Closures**
154//!
155//! Register any Rust function or async closure as a tool:
156//!
157//! ```rust,no_run
158//! use cloudllm::tool_protocols::CustomToolProtocol;
159//! use cloudllm::tool_protocol::{ToolMetadata, ToolResult};
160//! use std::sync::Arc;
161//!
162//! # #[tokio::main]
163//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
164//! let protocol = Arc::new(CustomToolProtocol::new());
165//!
166//! // Synchronous tool
167//! protocol.register_tool(
168//! ToolMetadata::new("add", "Add two numbers"),
169//! Arc::new(|params| {
170//! let a = params["a"].as_f64().unwrap_or(0.0);
171//! let b = params["b"].as_f64().unwrap_or(0.0);
172//! Ok(ToolResult::success(serde_json::json!({"result": a + b})))
173//! }),
174//! ).await;
175//!
176//! // Asynchronous tool
177//! protocol.register_async_tool(
178//! ToolMetadata::new("fetch", "Fetch data from a URL"),
179//! Arc::new(|params| {
180//! Box::pin(async move {
181//! let url = params["url"].as_str().unwrap_or("");
182//! Ok(ToolResult::success(serde_json::json!({"url": url})))
183//! })
184//! }),
185//! ).await;
186//! # Ok(())
187//! # }
188//! ```
189//!
190//! **Advanced Approach: Custom Protocol Implementation**
191//!
192//! For complex tools or integration with external systems, implement [`tool_protocol::ToolProtocol`]:
193//!
194//! ```rust,no_run
195//! use async_trait::async_trait;
196//! use cloudllm::tool_protocol::{ToolMetadata, ToolProtocol, ToolResult};
197//! use std::error::Error;
198//!
199//! pub struct DatabaseAdapter;
200//!
201//! #[async_trait]
202//! impl ToolProtocol for DatabaseAdapter {
203//! async fn execute(
204//! &self,
205//! tool_name: &str,
206//! parameters: serde_json::Value,
207//! ) -> Result<ToolResult, Box<dyn Error + Send + Sync>> {
208//! match tool_name {
209//! "query" => {
210//! let sql = parameters["sql"].as_str().unwrap_or("");
211//! // Execute actual database query
212//! Ok(ToolResult::success(serde_json::json!({"result": "data"})))
213//! }
214//! _ => Ok(ToolResult::failure("Unknown tool".into()))
215//! }
216//! }
217//!
218//! async fn list_tools(&self) -> Result<Vec<ToolMetadata>, Box<dyn Error + Send + Sync>> {
219//! Ok(vec![ToolMetadata::new("query", "Execute SQL query")])
220//! }
221//!
222//! async fn get_tool_metadata(
223//! &self,
224//! tool_name: &str,
225//! ) -> Result<ToolMetadata, Box<dyn Error + Send + Sync>> {
226//! Ok(ToolMetadata::new(tool_name, "Tool"))
227//! }
228//!
229//! fn protocol_name(&self) -> &str {
230//! "database"
231//! }
232//! }
233//! ```
234//!
235//! **Built-in Tools: Ready to Use**
236//!
237//! CloudLLM provides several production-ready tools:
238//! - [`tools::Calculator`] - Mathematical expressions and statistics
239//! - [`tools::Memory`] - Persistent TTL-aware key-value store
240//! - [`tools::HttpClient`] - Secure REST API calls with domain filtering
241//! - [`tools::BashTool`] - Safe command execution with timeouts
242//! - [`tools::FileSystemTool`] - Sandboxed file operations
243//!
244//! See the [`tools`] module for complete documentation on each tool.
245//!
246//! ## Getting Started
247//!
248//! ```rust,no_run
249//! use cloudllm::clients::openai::{Model, OpenAIClient};
250//! use cloudllm::client_wrapper::{ClientWrapper, Message, Role};
251//!
252//! #[tokio::main]
253//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
254//! cloudllm::init_logger();
255//!
256//! let api_key = std::env::var("OPEN_AI_SECRET")?;
257//! let client = OpenAIClient::new_with_model_enum(&api_key, Model::GPT5Nano);
258//!
259//! let response = client
260//! .send_message(
261//! &[
262//! Message { role: Role::System, content: "You are terse.".into(), tool_calls: vec![] },
263//! Message { role: Role::User, content: "Summarise CloudLLM in one sentence.".into(), tool_calls: vec![] },
264//! ],
265//! None,
266//! )
267//! .await?;
268//!
269//! println!("{}", response.content);
270//! Ok(())
271//! }
272//! ```
273//!
274//! Continue exploring the modules re-exported from the crate root for progressively richer
275//! interaction patterns.
276
277use std::sync::Once;
278
279static INIT_LOGGER: Once = Once::new();
280
281/// Initialise the global [`env_logger`] subscriber exactly once.
282///
283/// The helper is intentionally lightweight so that applications embedding CloudLLM can opt-in
284/// to simple `RUST_LOG` driven diagnostics without having to choose a specific logging backend
285/// upfront.
286///
287/// ```rust
288/// cloudllm::init_logger();
289/// log::info!("Logger is ready");
290/// ```
291pub fn init_logger() {
292 INIT_LOGGER.call_once(|| {
293 env_logger::init();
294 });
295}
296
297// Import the top-level `cloudllm` module.
298pub mod cloudllm;
299
300// Re-exporting key items for easier external access.
301pub use cloudllm::agent::Agent;
302pub use cloudllm::client_wrapper;
303pub use cloudllm::client_wrapper::{
304 ClientWrapper, LLMClientInfo, Message, MessageChunk, MessageChunkStream, MessageStreamFuture,
305 NativeToolCall, Role, ToolDefinition,
306};
307pub use cloudllm::clients;
308pub use cloudllm::config::CloudLLMConfig;
309pub use cloudllm::context_strategy;
310pub use cloudllm::context_strategy::{
311 ContextStrategy, NoveltyAwareStrategy, SelfCompressionStrategy, TrimStrategy,
312};
313pub use cloudllm::llm_session::LLMSession;
314pub use mcp;
315pub use mentisdb;
316pub use mentisdb::{
317 JsonlStorageAdapter, MentisDb, StorageAdapter, Thought, ThoughtInput, ThoughtQuery,
318 ThoughtRelation, ThoughtRelationKind, ThoughtRole, ThoughtType,
319};
320
321// Re-export tool protocol and orchestration functionality
322pub use cloudllm::event;
323pub use cloudllm::event::{AgentEvent, EventHandler, McpEvent, OrchestrationEvent, PlannerEvent};
324pub use cloudllm::mcp_server;
325pub use cloudllm::orchestration;
326pub use cloudllm::planner;
327pub use cloudllm::planner::{
328 BasicPlanner, MemoryEntry, MemoryStore, NoopMemory, NoopPolicy, NoopStream, Planner,
329 PlannerContext, PlannerOutcome, PlannerResult, PolicyDecision, PolicyEngine, StreamSink,
330 ToolCallRequest, UserMessage,
331};
332pub use cloudllm::tool_protocol;
333pub use cloudllm::tool_protocols;
334pub use cloudllm::tools;