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, 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, and custom OpenAI-
122//! compatible endpoints) is exposed as a `ClientWrapper` implementation.  All wrappers share
123//! the same ergonomics for synchronous calls, streaming, and token accounting.
124//!
125//! ### Multi-Agent Orchestration
126//!
127//! The [`orchestration`] module orchestrates conversations between multiple agents across a variety
128//! of collaboration patterns:
129//! - **Parallel**: All agents respond simultaneously with aggregated results
130//! - **RoundRobin**: Agents take sequential turns building on previous responses
131//! - **Moderated**: Agents propose ideas, moderator synthesizes the answer
132//! - **Hierarchical**: Lead agent coordinates, specialists handle specific aspects
133//! - **Debate**: Agents discuss and challenge until convergence
134//! - **Ralph**: Autonomous iterative loop working through a PRD task list
135//! - **AnthropicAgentTeams**: Decentralized task-based coordination where agents autonomously
136//!   discover, claim, and complete tasks from a shared pool with no central orchestrator
137//!
138//! ### Deploying Tool Servers with MCPServerBuilder
139//!
140//! Create standalone MCP servers that expose tools over HTTP with a simple builder API.
141//! Perfect for microservices or sharing tool capabilities across the network:
142//!
143//! For a complete MCP server example with HTTP support, see the `examples/mcp_server_all_tools.rs`
144//! example which demonstrates deploying all built-in tools via HTTP with authentication and IP filtering.
145//!
146//! MCPServerBuilder is available on the `mcp-server` feature (requires `axum` and `tower`).
147//!
148//! ### Creating Tools: Simple to Advanced
149//!
150//! Tools are the actions agents can take. CloudLLM supports multiple ways to create them:
151//!
152//! **Simple Approach: Rust Closures**
153//!
154//! Register any Rust function or async closure as a tool:
155//!
156//! ```rust,no_run
157//! use cloudllm::tool_protocols::CustomToolProtocol;
158//! use cloudllm::tool_protocol::{ToolMetadata, ToolResult};
159//! use std::sync::Arc;
160//!
161//! # #[tokio::main]
162//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
163//! let protocol = Arc::new(CustomToolProtocol::new());
164//!
165//! // Synchronous tool
166//! protocol.register_tool(
167//!     ToolMetadata::new("add", "Add two numbers"),
168//!     Arc::new(|params| {
169//!         let a = params["a"].as_f64().unwrap_or(0.0);
170//!         let b = params["b"].as_f64().unwrap_or(0.0);
171//!         Ok(ToolResult::success(serde_json::json!({"result": a + b})))
172//!     }),
173//! ).await;
174//!
175//! // Asynchronous tool
176//! protocol.register_async_tool(
177//!     ToolMetadata::new("fetch", "Fetch data from a URL"),
178//!     Arc::new(|params| {
179//!         Box::pin(async move {
180//!             let url = params["url"].as_str().unwrap_or("");
181//!             Ok(ToolResult::success(serde_json::json!({"url": url})))
182//!         })
183//!     }),
184//! ).await;
185//! # Ok(())
186//! # }
187//! ```
188//!
189//! **Advanced Approach: Custom Protocol Implementation**
190//!
191//! For complex tools or integration with external systems, implement [`tool_protocol::ToolProtocol`]:
192//!
193//! ```rust,no_run
194//! use async_trait::async_trait;
195//! use cloudllm::tool_protocol::{ToolMetadata, ToolProtocol, ToolResult};
196//! use std::error::Error;
197//!
198//! pub struct DatabaseAdapter;
199//!
200//! #[async_trait]
201//! impl ToolProtocol for DatabaseAdapter {
202//!     async fn execute(
203//!         &self,
204//!         tool_name: &str,
205//!         parameters: serde_json::Value,
206//!     ) -> Result<ToolResult, Box<dyn Error + Send + Sync>> {
207//!         match tool_name {
208//!             "query" => {
209//!                 let sql = parameters["sql"].as_str().unwrap_or("");
210//!                 // Execute actual database query
211//!                 Ok(ToolResult::success(serde_json::json!({"result": "data"})))
212//!             }
213//!             _ => Ok(ToolResult::failure("Unknown tool".into()))
214//!         }
215//!     }
216//!
217//!     async fn list_tools(&self) -> Result<Vec<ToolMetadata>, Box<dyn Error + Send + Sync>> {
218//!         Ok(vec![ToolMetadata::new("query", "Execute SQL query")])
219//!     }
220//!
221//!     async fn get_tool_metadata(
222//!         &self,
223//!         tool_name: &str,
224//!     ) -> Result<ToolMetadata, Box<dyn Error + Send + Sync>> {
225//!         Ok(ToolMetadata::new(tool_name, "Tool"))
226//!     }
227//!
228//!     fn protocol_name(&self) -> &str {
229//!         "database"
230//!     }
231//! }
232//! ```
233//!
234//! **Built-in Tools: Ready to Use**
235//!
236//! CloudLLM provides several production-ready tools:
237//! - [`tools::Calculator`] - Mathematical expressions and statistics
238//! - [`tools::Memory`] - Persistent TTL-aware key-value store
239//! - [`tools::HttpClient`] - Secure REST API calls with domain filtering
240//! - [`tools::BashTool`] - Safe command execution with timeouts
241//! - [`tools::FileSystemTool`] - Sandboxed file operations
242//!
243//! See the [`tools`] module for complete documentation on each tool.
244//!
245//! ## Getting Started
246//!
247//! ```rust,no_run
248//! use cloudllm::clients::openai::{Model, OpenAIClient};
249//! use cloudllm::client_wrapper::{ClientWrapper, Message, Role};
250//!
251//! #[tokio::main]
252//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
253//!     cloudllm::init_logger();
254//!
255//!     let api_key = std::env::var("OPEN_AI_SECRET")?;
256//!     let client = OpenAIClient::new_with_model_enum(&api_key, Model::GPT41Nano);
257//!
258//!     let response = client
259//!         .send_message(
260//!             &[
261//!                 Message { role: Role::System, content: "You are terse.".into(), tool_calls: vec![] },
262//!                 Message { role: Role::User, content: "Summarise CloudLLM in one sentence.".into(), tool_calls: vec![] },
263//!             ],
264//!             None,
265//!         )
266//!         .await?;
267//!
268//!     println!("{}", response.content);
269//!     Ok(())
270//! }
271//! ```
272//!
273//! Continue exploring the modules re-exported from the crate root for progressively richer
274//! interaction patterns.
275
276use std::sync::Once;
277
278static INIT_LOGGER: Once = Once::new();
279
280/// Initialise the global [`env_logger`] subscriber exactly once.
281///
282/// The helper is intentionally lightweight so that applications embedding CloudLLM can opt-in
283/// to simple `RUST_LOG` driven diagnostics without having to choose a specific logging backend
284/// upfront.
285///
286/// ```rust
287/// cloudllm::init_logger();
288/// log::info!("Logger is ready");
289/// ```
290pub fn init_logger() {
291    INIT_LOGGER.call_once(|| {
292        env_logger::init();
293    });
294}
295
296// Import the top-level `cloudllm` module.
297pub mod cloudllm;
298
299// Re-exporting key items for easier external access.
300pub use cloudllm::agent::Agent;
301pub use cloudllm::client_wrapper;
302pub use cloudllm::client_wrapper::{
303    ClientWrapper, Message, MessageChunk, MessageChunkStream, MessageStreamFuture, NativeToolCall,
304    Role, ToolDefinition,
305};
306pub use cloudllm::clients;
307pub use cloudllm::config::CloudLLMConfig;
308pub use cloudllm::context_strategy;
309pub use cloudllm::context_strategy::{
310    ContextStrategy, NoveltyAwareStrategy, SelfCompressionStrategy, TrimStrategy,
311};
312pub use cloudllm::llm_session::LLMSession;
313pub use cloudllm::thought_chain;
314pub use cloudllm::thought_chain::{Thought, ThoughtChain, ThoughtType};
315
316// Re-export tool protocol and orchestration functionality
317pub use cloudllm::event;
318pub use cloudllm::event::{AgentEvent, EventHandler, McpEvent, OrchestrationEvent, PlannerEvent};
319pub use cloudllm::mcp_server;
320pub use cloudllm::orchestration;
321pub use cloudllm::planner;
322pub use cloudllm::planner::{
323    BasicPlanner, MemoryEntry, MemoryStore, NoopMemory, NoopPolicy, NoopStream, Planner,
324    PlannerContext, PlannerOutcome, PlannerResult, PolicyDecision, PolicyEngine, StreamSink,
325    ToolCallRequest, UserMessage,
326};
327pub use cloudllm::tool_protocol;
328pub use cloudllm::tool_protocols;
329pub use cloudllm::tools;