1use std::env;
2
3use clap::Parser;
4use oy_agent::Orchestrator;
5use oy_agent::infrastructure::agents::main_agent::MainAgent;
6use oy_agent::infrastructure::tools::edit::EditTool;
7use oy_agent::infrastructure::tools::read::ReadTool;
8use oy_agent::infrastructure::tools::write::WriteTool;
9use oy_agent::infrastructure::tools::{ToolRegistry, bash::BashTool};
10use oy_ai::{AiConfig, OpenCodeGoProvider};
11use serde::Deserialize;
12
13#[derive(Parser, Debug)]
15#[command(author, version, about)]
16pub struct CliArgs {
17 #[arg(short = 'p', long)]
19 pub prompt: Option<String>,
20
21 #[arg(short = 'm', long)]
22 pub model: Option<String>,
23}
24
25#[derive(Debug, Deserialize, Default)]
27pub struct CliConfig {
28 pub api_key: Option<String>,
29 pub base_url: Option<String>,
30 pub model: Option<String>,
31}
32
33impl CliConfig {
34 pub fn load() -> Self {
36 let home = match dirs::home_dir() {
37 Some(h) => h,
38 None => return Self::default(),
39 };
40 let config_path = home.join(".oy-ai-agent").join("config.toml");
41 if !config_path.exists() {
42 return Self::default();
43 }
44 match std::fs::read_to_string(&config_path) {
45 Ok(content) => toml::from_str(&content).unwrap_or_default(),
46 Err(_) => Self::default(),
47 }
48 }
49}
50
51pub fn build_provider_config(cli_config: &CliConfig, cli_args: &CliArgs) -> AiConfig {
61 let api_key = cli_config
62 .api_key
63 .clone()
64 .or_else(|| env::var("OPENROUTER_API_KEY").ok())
65 .unwrap_or_else(|| {
66 eprintln!(
67 "OPENROUTER_API_KEY is not set. Set it in ~/.oy-ai-agent/config.toml \
68 or the OPENROUTER_API_KEY environment variable."
69 );
70 std::process::exit(1);
71 });
72
73 let base_url = cli_config
74 .base_url
75 .clone()
76 .or_else(|| env::var("OPENROUTER_BASE_URL").ok())
77 .unwrap_or_else(|| "https://openrouter.ai/api/v1".to_string());
78
79 let model = cli_args
80 .model
81 .clone()
82 .or_else(|| cli_config.model.clone())
83 .or_else(|| env::var("OPENROUTER_MODEL").ok())
84 .unwrap_or_else(|| "anthropic/claude-haiku-4.5".to_string());
85
86 AiConfig::new(base_url, api_key, model)
87}
88
89pub fn register_default_tools(registry: &mut ToolRegistry) {
91 registry.register(ReadTool);
92 registry.register(WriteTool);
93 registry.register(EditTool);
94 registry.register(BashTool);
95}
96
97pub async fn run(args: CliArgs) -> Result<(), anyhow::Error> {
99 if args.prompt.is_none() {
101 oy_tui::run_tui()
102 .await
103 .map_err(|e| anyhow::Error::msg(format!("{}", e)))?;
104 return Ok(());
105 }
106
107 let prompt = args.prompt.as_ref().unwrap();
108 let cli_config = CliConfig::load();
109 let ai_config = build_provider_config(&cli_config, &args);
110
111 eprintln!("url:{}", ai_config.base_url);
112 eprintln!(
113 "key:{}...",
114 &ai_config.api_key[..8.min(ai_config.api_key.len())]
115 );
116
117 let provider = OpenCodeGoProvider::new(ai_config);
118 let mut registry = ToolRegistry::new();
119 register_default_tools(&mut registry);
120
121 let main_agent = MainAgent::new_with_max_iterations(None);
122 let mut orchestrator = Orchestrator::new(main_agent, provider, registry);
123 orchestrator.init();
124 let result = orchestrator.execute(prompt).await?;
125 println!("{}", result);
126 Ok(())
127}