Skip to main content

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;