Skip to main content

appam/
lib.rs

1//! Appam: AI Agent Framework
2//!
3//! A comprehensive framework for building AI agents with minimal configuration.
4//! Create powerful agents by writing TOML configs, tool definitions, and tool
5//! implementations in Rust or Python.
6//!
7//! # Overview
8//!
9//! Appam provides:
10//! - **Agent system**: Define agents with system prompts and tool sets
11//! - **Tool framework**: Implement tools in Rust or Python with automatic loading
12//! - **LLM integration**: Streaming OpenRouter client with tool calling
13//! - **OpenAI Codex auth**: Local OAuth cache for ChatGPT Codex subscription access
14//! - **Configuration**: Hierarchical TOML-based configuration
15//! - **Interfaces**: Built-in TUI and web API
16//! - **Logging**: Structured tracing and session transcripts
17//!
18//! # Quick Start
19//!
20//! ## Option 1: Pure Rust SDK (No TOML Required)
21//!
22//! Build agents entirely in Rust with the builder API:
23//!
24//! ```no_run
25//! use appam::prelude::*;
26//! use anyhow::Result;
27//! use std::sync::Arc;
28//! # use serde_json::{json, Value};
29//! # struct MyTool;
30//! # impl Tool for MyTool {
31//! #     fn name(&self) -> &str { "my_tool" }
32//! #     fn spec(&self) -> Result<ToolSpec> {
33//! #         Ok(serde_json::from_value(json!({
34//! #             "type": "function",
35//! #             "function": {
36//! #                 "name": "my_tool",
37//! #                 "description": "Example tool",
38//! #                 "parameters": {"type": "object", "properties": {}}
39//! #             }
40//! #         }))?)
41//! #     }
42//! #     fn execute(&self, _: Value) -> Result<Value> { Ok(json!({"output": "result"})) }
43//! # }
44//!
45//! #[tokio::main]
46//! async fn main() -> Result<()> {
47//!     let agent = AgentBuilder::new("my-agent")
48//!         .model("openai/gpt-4o-mini")
49//!         .system_prompt("You are a helpful AI assistant.")
50//!         .with_tool(Arc::new(MyTool))
51//!         .build()?;
52//!
53//!     agent.run("Hello!").await?;
54//!     Ok(())
55//! }
56//! ```
57//!
58//! ## Option 2: TOML Configuration
59//!
60//! Create an agent configuration file (`agent.toml`):
61//!
62//! ```toml
63//! [agent]
64//! name = "assistant"
65//! model = "openai/gpt-5"
66//! system_prompt = "prompt.txt"
67//!
68//! [[tools]]
69//! name = "bash"
70//! schema = "tools/bash.json"
71//! implementation = { type = "python", script = "tools/bash.py" }
72//! ```
73//!
74//! Load and run the agent:
75//!
76//! ```no_run
77//! use appam::prelude::*;
78//! use anyhow::Result;
79//!
80//! #[tokio::main]
81//! async fn main() -> Result<()> {
82//!     let agent = TomlAgent::from_file("agent.toml")?;
83//!     agent.run("What can you do?").await?;
84//!     Ok(())
85//! }
86//! ```
87//!
88//! ## Option 3: Hybrid Approach
89//!
90//! Load from TOML and extend with Rust tools:
91//!
92//! ```no_run
93//! # use appam::prelude::*;
94//! # use anyhow::Result;
95//! # use std::sync::Arc;
96//! # use serde_json::{json, Value};
97//! # struct CustomTool;
98//! # impl Tool for CustomTool {
99//! #     fn name(&self) -> &str { "custom" }
100//! #     fn spec(&self) -> Result<ToolSpec> {
101//! #         Ok(serde_json::from_value(json!({
102//! #             "type": "function",
103//! #             "function": {
104//! #                 "name": "custom",
105//! #                 "description": "Custom tool",
106//! #                 "parameters": {"type": "object", "properties": {}}
107//! #             }
108//! #         }))?)
109//! #     }
110//! #     fn execute(&self, _: Value) -> Result<Value> { Ok(json!({"output": "result"})) }
111//! # }
112//! # async fn example() -> Result<()> {
113//! let agent = TomlAgent::from_file("agent.toml")?
114//!     .with_additional_tool(Arc::new(CustomTool));
115//!
116//! agent.run("Use custom tool").await?;
117//! # Ok(())
118//! # }
119//! ```
120//!
121//! # Architecture
122//!
123//! ## Agents
124//!
125//! Agents are defined by:
126//! - A **system prompt** that establishes behavior and capabilities
127//! - A **tool set** that provides executable functions
128//! - A **model** that powers the agent's reasoning
129//!
130//! The `Agent` trait provides the core interface. Use `TomlAgent` to load
131//! agents from configuration files.
132//!
133//! ## Tools
134//!
135//! Tools are executable functions exposed to the LLM. Each tool has:
136//! - A **JSON schema** defining parameters and description
137//! - An **implementation** in Rust or Python
138//!
139//! Tools can be implemented as:
140//! - **Rust**: Native performance, type safety, full access to Rust ecosystem
141//! - **Python**: Easy prototyping, access to Python libraries
142//!
143//! ## Configuration
144//!
145//! Configuration is hierarchical:
146//! 1. Default values (hardcoded)
147//! 2. Global config (`appam.toml`)
148//! 3. Agent config (per-agent TOML file)
149//! 4. Environment variables (highest priority)
150//!
151//! ## Interfaces
152//!
153//! Run agents via:
154//! - **TUI**: Interactive terminal interface with rich widgets
155//! - **CLI**: Simple streaming output
156//! - **Web API**: RESTful API with Server-Sent Events streaming
157//!
158//! # Examples
159//!
160//! ## Creating a Python Tool
161//!
162//! Define the schema (`echo.json`):
163//!
164//! ```json
165//! {
166//!   "type": "function",
167//!   "function": {
168//!     "name": "echo",
169//!     "description": "Echo back the input message",
170//!     "parameters": {
171//!       "type": "object",
172//!       "properties": {
173//!         "message": {
174//!           "type": "string",
175//!           "description": "Message to echo"
176//!         }
177//!       },
178//!       "required": ["message"]
179//!     }
180//!   }
181//! }
182//! ```
183//!
184//! Implement the tool (`echo.py`):
185//!
186//! ```python
187//! def execute(args):
188//!     """Echo the input message."""
189//!     return {"output": args.get("message", "")}
190//! ```
191//!
192//! Register in agent config:
193//!
194//! ```toml
195//! [[tools]]
196//! name = "echo"
197//! schema = "tools/echo.json"
198//! implementation = { type = "python", script = "tools/echo.py" }
199//! ```
200//!
201//! ## Programmatic Agent Creation
202//!
203//! ```no_run
204//! use appam::agent::{Agent, TomlAgent};
205//! use appam::tools::{Tool, ToolRegistry};
206//! use std::sync::Arc;
207//!
208//! async fn create_custom_agent() {
209//!     let agent = TomlAgent::from_file("agent.toml")
210//!         .unwrap()
211//!         .with_model("anthropic/claude-3.5-sonnet");
212//!
213//!     // Run with custom prompt
214//!     agent.run("Analyze this codebase").await.unwrap();
215//! }
216//! ```
217
218#![warn(missing_docs)]
219#![warn(clippy::all)]
220#![allow(clippy::module_inception)]
221
222pub mod agent;
223pub mod config;
224pub mod http;
225pub mod llm;
226pub mod logging;
227pub mod tools;
228pub mod web;
229
230// TODO: Implement these modules in future phases
231// pub mod interface;
232
233// Re-export commonly used types for convenience
234pub use agent::history::SessionHistory;
235pub use agent::{Agent, AgentBuilder, RuntimeAgent, Session, TomlAgent};
236pub use config::{
237    load_config_from_env, load_global_config, AgentConfigBuilder, AppConfig, AppConfigBuilder,
238    HistoryConfig, LogFormat, LoggingConfig, TraceFormat,
239};
240pub use llm::{
241    DynamicLlmClient, LlmClient, LlmProvider, UnifiedMessage, UnifiedTool, UnifiedToolCall,
242};
243pub use tools::{Tool, ToolRegistry};
244
245// Re-export procedural macros
246pub use appam_macros::{tool, Schema};
247
248/// Prelude module for convenient imports.
249///
250/// Import everything you need with:
251///
252/// ```
253/// use appam::prelude::*;
254/// ```
255/// Prelude module for convenient imports
256///
257/// Import everything you need with `use appam::prelude::*;`
258///
259/// # Examples
260///
261/// ```no_run
262/// use appam::prelude::*;
263/// use anyhow::Result;
264///
265/// #[tokio::main]
266/// async fn main() -> Result<()> {
267///     // Use Agent::quick() for one-liner creation
268///     let agent = Agent::quick(
269///         "anthropic/claude-sonnet-4-5",
270///         "You are helpful.",
271///         vec![],
272///     )?;
273///
274///     // Use closure-based streaming
275///     agent
276///         .stream("Hello")
277///         .on_content(|text| print!("{}", text))
278///         .run()
279///         .await?;
280///
281///     Ok(())
282/// }
283/// ```
284pub mod prelude {
285    // Core agent types
286    pub use crate::agent::Agent as AgentTrait;
287    pub use crate::agent::{AgentBuilder, RuntimeAgent, Session, TomlAgent}; // The trait
288
289    // Quick constructors and shortcuts (NEW!)
290    pub use crate::agent::quick::{Agent, AgentBuilderToolExt, AgentQuick};
291
292    // Streaming types
293    pub use crate::agent::streaming::{StreamConsumer, StreamEvent};
294    pub use crate::agent::streaming_builder::StreamBuilder;
295
296    // Consumers
297    pub use crate::agent::consumers::{
298        CallbackConsumer, ChannelConsumer, ConsoleConsumer, TraceConsumer,
299    };
300
301    // Error types (NEW!)
302    pub use crate::agent::errors::{analyze_tool_error, ToolExecutionError};
303
304    // History
305    pub use crate::agent::history::{SessionHistory, SessionSummary};
306
307    // Configuration
308    pub use crate::config::{
309        load_config_from_env, load_global_config, AgentConfigBuilder, AppConfig, AppConfigBuilder,
310        HistoryConfig, LogFormat, LoggingConfig, TraceFormat,
311    };
312
313    // LLM types
314    pub use crate::llm::{
315        ChatMessage, DynamicLlmClient, LlmClient, LlmProvider, Role, ToolSpec, UnifiedMessage,
316        UnifiedTool, UnifiedToolCall,
317    };
318
319    // Tool system
320    pub use crate::tools::register::{ClosureTool, ToolRegistryExt};
321    pub use crate::tools::{Tool, ToolRegistry};
322
323    // Procedural macros - the star of the DX improvements! (NEW!)
324    pub use appam_macros::{tool, Schema};
325
326    // Re-export common external types for convenience
327    pub use anyhow::{anyhow, bail, Context, Result};
328    pub use serde::{Deserialize, Serialize};
329    pub use serde_json::{json, Value};
330    pub use std::sync::Arc;
331    pub use tokio;
332}