aether_pilot_service/
aether_pilot_service.rs

1use aether_api::{serve_pilot_http_service, PilotServiceConfig};
2use std::{env, path::PathBuf};
3
4fn parse_config_path() -> Result<PathBuf, String> {
5    let mut args = env::args().skip(1);
6    let mut config_path = None;
7
8    while let Some(argument) = args.next() {
9        match argument.as_str() {
10            "--config" => {
11                let value = args
12                    .next()
13                    .ok_or_else(|| "--config requires a path".to_string())?;
14                config_path = Some(PathBuf::from(value));
15            }
16            "--help" | "-h" => {
17                println!(
18                    "Usage: aether_pilot_service --config <path>\n       AETHER_PILOT_CONFIG=<path> aether_pilot_service"
19                );
20                std::process::exit(0);
21            }
22            other => {
23                return Err(format!("unrecognized argument: {other}"));
24            }
25        }
26    }
27
28    config_path
29        .or_else(|| env::var_os("AETHER_PILOT_CONFIG").map(PathBuf::from))
30        .ok_or_else(|| {
31            "missing pilot service config path; pass --config <path> or set AETHER_PILOT_CONFIG"
32                .into()
33        })
34}
35
36#[tokio::main]
37async fn main() -> Result<(), Box<dyn std::error::Error>> {
38    let config_path = parse_config_path()
39        .map_err(|message| std::io::Error::new(std::io::ErrorKind::InvalidInput, message))?;
40    let config = PilotServiceConfig::load(&config_path)?.resolve(&config_path)?;
41
42    println!("AETHER pilot HTTP service");
43    println!("  config: {}", config_path.display());
44    println!("  storage: {}", config.database_path.display());
45    println!("  sidecars: {}", config.sidecar_path().display());
46    println!("  audit log: {}", config.audit_log_path.display());
47    println!("  listening: http://{}", config.bind_addr);
48    println!("  configured principals:");
49    for token in &config.token_summaries {
50        let scopes = token
51            .scopes
52            .iter()
53            .map(|scope| format!("{scope:?}").to_lowercase())
54            .collect::<Vec<_>>()
55            .join(", ");
56        let policy = token
57            .policy_context
58            .as_ref()
59            .map(|policy| {
60                format!(
61                    "capabilities={:?} visibilities={:?}",
62                    policy.capabilities, policy.visibilities
63                )
64            })
65            .unwrap_or_else(|| "public".into());
66        println!(
67            "    - {} [{}] via {} ({})",
68            token.principal, scopes, token.source, policy
69        );
70    }
71    println!("  GET  /health");
72    println!("  GET  /v1/status");
73    println!("  GET  /v1/audit");
74    println!("  POST /v1/admin/auth/reload");
75    println!("  GET  /v1/history");
76    println!("  POST /v1/append");
77    println!("  POST /v1/state/current");
78    println!("  POST /v1/state/as-of");
79    println!("  POST /v1/documents/parse");
80    println!("  POST /v1/documents/run");
81    println!("  POST /v1/reports/pilot/coordination-delta");
82    println!("  POST /v1/explain/tuple");
83    println!("  POST /v1/sidecars/artifacts/register");
84    println!("  POST /v1/sidecars/artifacts/get");
85    println!("  POST /v1/sidecars/vectors/register");
86    println!("  POST /v1/sidecars/vectors/search");
87
88    serve_pilot_http_service(config).await?;
89    Ok(())
90}