1pub mod agents;
18pub mod config;
19pub mod error;
20pub mod event;
21pub mod logger;
22pub mod models;
23pub mod normalize;
24pub mod process;
25pub mod registry;
26pub mod runner;
27pub mod settings;
28
29pub use config::{AgentKind, OutputFormat, PermissionMode, TaskConfig, TaskConfigBuilder};
30pub use error::{Error, Result};
31pub use event::{Event, UsageData};
32pub use models::{ModelEntry, ModelRegistry, ModelResolution};
33pub use normalize::NormalizeConfig;
34pub use process::StreamHandle;
35pub use runner::{AgentCapabilities, AgentRunner, EventStream};
36
37pub use tokio_util::sync::CancellationToken;
39
40pub async fn run_task(config: &TaskConfig) -> Result<EventStream> {
45 let handle = run_task_with_cancel(config, None).await?;
46 Ok(handle.stream)
47}
48
49pub async fn run_task_with_cancel(
54 config: &TaskConfig,
55 cancel_token: Option<tokio_util::sync::CancellationToken>,
56) -> Result<StreamHandle> {
57 let runner = agents::create_runner(config.agent);
58
59 if config.binary_path.is_none() && !runner.is_available() {
62 return Err(Error::BinaryNotFound {
63 agent: config.agent.display_name().to_string(),
64 binary: config.agent.default_binary().to_string(),
65 });
66 }
67
68 let mut handle = runner.run(config, cancel_token).await?;
69
70 let norm_config = NormalizeConfig {
71 cwd: config
72 .cwd
73 .as_ref()
74 .map(|p| p.display().to_string())
75 .or_else(|| std::env::current_dir().ok().map(|p| p.display().to_string())),
76 model: config.model.clone(),
77 prompt: Some(config.prompt.clone()),
78 };
79 handle.stream = normalize::normalize_stream(handle.stream, norm_config);
80
81 Ok(handle)
82}
83
84pub fn available_agents() -> Vec<AgentKind> {
86 use AgentKind::*;
87 [Claude, OpenCode, Codex, Cursor]
88 .into_iter()
89 .filter(|kind| {
90 let runner = agents::create_runner(*kind);
91 runner.is_available()
92 })
93 .collect()
94}