Skip to main content

tiny_agent_rs/cli/
mod.rs

1use crate::{
2    tools::{CalculatorTool, WeatherTool},
3    Agent, FunctionFactory,
4};
5use clap::{Arg, Command};
6use dotenvy;
7use std::env;
8use tracing::{error, info};
9
10/// CLI entry point for the tiny-agent tool
11pub async fn run() -> Result<(), Box<dyn std::error::Error>> {
12    // Load environment variables from .env file
13    dotenvy::dotenv().ok();
14    tracing_subscriber::fmt::init();
15
16    let matches = Command::new("tiny-agent")
17        .version("0.1.0")
18        .about("A lightweight Rust agent for LLM tool calling with OpenRouter")
19        .arg(
20            Arg::new("prompt")
21                .help("The prompt to send to the agent")
22                .required(true)
23                .index(1),
24        )
25        .arg(
26            Arg::new("model")
27                .short('m')
28                .long("model")
29                .value_name("MODEL")
30                .help("The OpenRouter model to use")
31                .default_value("openai/gpt-4.1-mini"),
32        )
33        .arg(
34            Arg::new("api-key")
35                .short('k')
36                .long("api-key")
37                .value_name("KEY")
38                .help("OpenRouter API key (or set OPENAI_API_KEY env var)"),
39        )
40        .arg(
41            Arg::new("base-url")
42                .short('u')
43                .long("base-url")
44                .value_name("URL")
45                .help(
46                    "OpenRouter base URL (or set OPENAI_BASE_URL / OPENROUTER_BASE_URL env vars)",
47                ),
48        )
49        .arg(
50            Arg::new("timeout")
51                .short('t')
52                .long("timeout")
53                .value_name("SECONDS")
54                .help("Request timeout in seconds")
55                .default_value("120"),
56        )
57        .arg(
58            Arg::new("max-iterations")
59                .short('i')
60                .long("max-iterations")
61                .value_name("COUNT")
62                .help("Maximum agent iterations")
63                .default_value("10"),
64        )
65        .get_matches();
66
67    // Get API key from argument or environment
68    let api_key = matches
69        .get_one::<String>("api-key")
70        .cloned()
71        .or_else(|| env::var("OPENAI_API_KEY").ok())
72        .ok_or("OpenRouter API key is required. Set OPENAI_API_KEY environment variable or use --api-key")?;
73
74    // Resolve base URL from CLI or environment
75    let base_url = matches
76        .get_one::<String>("base-url")
77        .cloned()
78        .or_else(|| env::var("OPENAI_BASE_URL").ok())
79        .or_else(|| env::var("OPENROUTER_BASE_URL").ok())
80        .unwrap_or_else(|| "https://openrouter.ai/api/v1".to_string());
81
82    // Set up function factory with tools
83    let mut function_factory = FunctionFactory::new();
84    function_factory.register_tool(CalculatorTool::new());
85    function_factory.register_tool(WeatherTool::new());
86
87    // Create agent
88    let timeout_seconds: u64 = matches.get_one::<String>("timeout").unwrap().parse()?;
89    let max_iterations: usize = matches
90        .get_one::<String>("max-iterations")
91        .unwrap()
92        .parse()?;
93
94    let agent = Agent::new(api_key, function_factory)
95        .with_model(matches.get_one::<String>("model").unwrap().as_str())
96        .with_timeout(std::time::Duration::from_secs(timeout_seconds))
97        .with_max_iterations(max_iterations)
98        .with_base_url(base_url.clone());
99
100    // Run the agent
101    let prompt = matches.get_one::<String>("prompt").unwrap();
102    info!("Running agent with prompt: {}", prompt);
103    info!(
104        "Using model: {}",
105        matches.get_one::<String>("model").unwrap()
106    );
107    info!("Base URL: {}", base_url);
108
109    match agent.run(prompt).await {
110        Ok(response) => {
111            println!("\nAgent Response:\n{}", response);
112            info!("Agent execution completed successfully");
113        }
114        Err(e) => {
115            error!("Agent execution failed: {}", e);
116            return Err(e.into());
117        }
118    }
119
120    Ok(())
121}