Skip to main content

bamboo_agent/
lib.rs

1//! Bamboo - A fully self-contained AI agent backend framework
2//!
3//! Bamboo provides a complete backend system for AI agents, including:
4//! - Built-in HTTP/HTTPS server (Actix-web)
5//! - Agent execution loop with tool support
6//! - LLM provider integrations (OpenAI, Anthropic, Google Gemini, GitHub Copilot)
7//! - Session management and persistence
8//! - Workflow and slash command systems
9//! - Process management for external tools
10//! - Claude Code integration
11//!
12//! # Features
13//!
14//! - **Dual mode**: Binary (standalone server) or library (embedded)
15//! - **Unified directory**: All data in the Bamboo data directory (default `${HOME}/.bamboo`)
16//! - **Production-ready**: Built-in CORS, rate limiting, security headers
17//!
18//! # Quick Start
19//!
20//! ## Binary Mode
21
22// Allow some clippy lints that are pre-existing
23#![allow(clippy::module_inception)]
24#![allow(clippy::doc_overindented_list_items)]
25#![allow(clippy::incompatible_msrv)]
26//!
27//! ```bash
28//! bamboo serve --port 9562 --data-dir "$HOME/.bamboo"
29//! ```
30//!
31//! ## Library Mode
32//!
33//! ```rust,ignore
34//! use bamboo_agent::{BambooServer, core::Config};
35//!
36//! #[tokio::main]
37//! async fn main() {
38//!     let config = Config::new();
39//!     let server = BambooServer::new(config);
40//!     server.start().await.unwrap();
41//! }
42//! ```
43
44use std::path::PathBuf;
45
46pub mod error;
47
48// Placeholder modules (will be populated during migration)
49pub mod agent;
50pub mod claude;
51pub mod commands;
52pub mod core;
53pub mod process;
54pub mod server;
55
56// Ergonomic module re-exports for the agent subsystem (keeps docs and external
57// imports stable without forcing callers through `bamboo_agent::agent::*`).
58pub use agent::{llm, skill, tools};
59
60// Re-export core Config as the primary configuration type
61pub use core::config::ServerConfig;
62pub use core::Config;
63pub use error::{BambooError, Result};
64pub use process::ProcessRegistry;
65
66/// Main Bamboo server instance
67pub struct BambooServer {
68    config: core::Config,
69    #[allow(dead_code)]
70    data_dir: PathBuf,
71}
72
73impl BambooServer {
74    /// Create a new Bamboo server with configuration
75    pub fn new(config: core::Config) -> Self {
76        Self {
77            config,
78            data_dir: core::paths::bamboo_dir(),
79        }
80    }
81
82    /// Create a new Bamboo server with an explicit data directory.
83    pub fn new_with_data_dir(config: core::Config, data_dir: PathBuf) -> Self {
84        Self { config, data_dir }
85    }
86
87    /// Start the HTTP server (blocking).
88    ///
89    /// Delegates to the appropriate server entrypoint based on the configuration:
90    /// - If `static_dir` is set, serves static files alongside the API (Docker mode).
91    /// - Otherwise, runs the API server with the configured bind address and port.
92    ///
93    /// This method blocks until the server shuts down.
94    pub async fn start(self) -> Result<()> {
95        core::paths::init_bamboo_dir(self.data_dir.clone());
96
97        let result = if self.config.server.static_dir.is_some() {
98            server::run_with_bind_and_static(
99                self.data_dir,
100                self.config.server.port,
101                &self.config.server.bind,
102                self.config.server.static_dir.clone(),
103            )
104            .await
105        } else if self.config.server.bind == "127.0.0.1" {
106            server::run(self.data_dir, self.config.server.port).await
107        } else {
108            server::run_with_bind(
109                self.data_dir,
110                self.config.server.port,
111                &self.config.server.bind,
112            )
113            .await
114        };
115
116        result.map_err(BambooError::HttpServer)
117    }
118
119    /// Get the server address
120    pub fn server_addr(&self) -> String {
121        self.config.server_addr()
122    }
123}
124
125/// Builder pattern for creating BambooServer
126///
127/// Provides a fluent API for configuring and instantiating a BambooServer.
128///
129/// # Example
130///
131/// ```rust,ignore
132/// use bamboo_agent::{BambooBuilder, BambooServer};
133/// use std::path::PathBuf;
134///
135/// let server = BambooBuilder::new()
136///     .port(9562)
137///     .bind("127.0.0.1")
138///     .data_dir(PathBuf::from("/path/to/bamboo-data-dir"))
139///     .build()
140///     .unwrap();
141/// ```
142pub struct BambooBuilder {
143    config: core::Config,
144    data_dir: PathBuf,
145}
146
147impl BambooBuilder {
148    /// Create a new BambooBuilder with default configuration
149    pub fn new() -> Self {
150        Self {
151            config: core::Config::new(),
152            data_dir: core::paths::bamboo_dir(),
153        }
154    }
155
156    /// Set the server port
157    ///
158    /// # Arguments
159    ///
160    /// * `port` - Port number to listen on
161    pub fn port(mut self, port: u16) -> Self {
162        self.config.server.port = port;
163        self
164    }
165
166    /// Set the bind address
167    ///
168    /// # Arguments
169    ///
170    /// * `addr` - IP address to bind to (e.g., "127.0.0.1", "0.0.0.0")
171    pub fn bind(mut self, addr: impl Into<String>) -> Self {
172        self.config.server.bind = addr.into();
173        self
174    }
175
176    /// Set the data directory for storing configuration and data
177    ///
178    /// # Arguments
179    ///
180    /// * `dir` - Path to the data directory
181    pub fn data_dir(mut self, dir: PathBuf) -> Self {
182        self.data_dir = dir;
183        self
184    }
185
186    /// Set the static files directory
187    ///
188    /// # Arguments
189    ///
190    /// * `dir` - Path to static files directory
191    pub fn static_dir(mut self, dir: PathBuf) -> Self {
192        self.config.server.static_dir = Some(dir);
193        self
194    }
195
196    /// Set the number of workers
197    ///
198    /// # Arguments
199    ///
200    /// * `workers` - Number of worker threads
201    pub fn workers(mut self, workers: usize) -> Self {
202        self.config.server.workers = workers;
203        self
204    }
205
206    /// Build the BambooServer instance
207    ///
208    /// # Returns
209    ///
210    /// A Result containing the configured BambooServer or an error
211    pub fn build(self) -> Result<BambooServer> {
212        Ok(BambooServer::new_with_data_dir(self.config, self.data_dir))
213    }
214}
215
216impl Default for BambooBuilder {
217    fn default() -> Self {
218        Self::new()
219    }
220}