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;