fn main() {
#[cfg(feature = "cli")]
{
use tokio::runtime::Runtime;
let rt = Runtime::new().expect("Failed to create Tokio runtime");
if let Err(e) = rt.block_on(run()) {
eprintln!("Error: {e}");
std::process::exit(1);
}
}
#[cfg(not(feature = "cli"))]
{
eprintln!("This binary requires the `cli` feature. Rebuild with:");
eprintln!(" cargo build --features cli");
}
}
#[cfg(feature = "cli")]
async fn run() -> anyhow::Result<()> {
use clap::Parser;
use std::env;
use x_ai::api_key::ApiKeyRequestBuilder;
use x_ai::chat_compl::{ChatCompletionsRequestBuilder, Message};
use x_ai::cli::{Cli, Command};
use x_ai::client::XaiClient;
use x_ai::completions::CompletionsRequestBuilder;
use x_ai::embedding::EmbeddingRequestBuilder;
use x_ai::get_mod::ModelRequestBuilder;
use x_ai::list_mod::ReducedModelListRequestBuilder;
use x_ai::traits::{
ApiKeyFetcher, ChatCompletionsFetcher, ClientConfig, CompletionsFetcher, EmbeddingFetcher,
ListModelFetcher, ModelInfoFetcher,
};
use x_ai::tui::run_tui;
let args = Cli::parse();
let api_key = args
.api_key
.unwrap_or_else(|| env::var("XAI_API_KEY").unwrap_or_default());
let model = args
.model
.unwrap_or_else(|| env::var("XAI_MODEL").unwrap_or_else(|_| "grok-4".to_string()));
let client = XaiClient::builder().build()?;
client.set_api_key(api_key.clone());
match args.cmd {
Some(Command::Chat(cmd)) => {
let messages = vec![Message::text("user", cmd.text)];
let builder =
ChatCompletionsRequestBuilder::new(client.clone(), model.clone(), messages);
let request = builder.clone().build()?;
let resp = builder.create_chat_completion(request).await?;
let content = resp
.choices
.first()
.map(|c| c.message.content.to_string())
.unwrap_or_default();
println!("{}", content);
}
Some(Command::Complete(cmd)) => {
let builder = CompletionsRequestBuilder::new(client.clone(), model.clone(), cmd.prompt)
.max_tokens(cmd.max_tokens);
let request = builder.clone().build()?;
let resp = builder.create_completions(request).await?;
let text = resp
.choices
.first()
.map(|c| c.text.clone())
.unwrap_or_default();
println!("{}", text);
}
Some(Command::Embed(cmd)) => {
let builder = EmbeddingRequestBuilder::new(
client.clone(),
model.clone(),
vec![cmd.text],
cmd.encoding_format,
);
let request = builder.clone().build()?;
let resp = builder.create_embedding(request).await?;
println!("{:?}", resp.data);
}
Some(Command::Models(_)) => {
let builder = ReducedModelListRequestBuilder::new(client.clone());
let resp = builder.fetch_model_info().await?;
for m in resp.data {
println!(" • {} (owned by: {})", m.id, m.owned_by);
}
}
Some(Command::Model(cmd)) => {
let builder = ModelRequestBuilder::new(client.clone(), cmd.model_id);
let info = builder.fetch_model_info().await?;
println!("ID: {}", info.id);
println!("Object: {}", info.object);
println!("Owned by: {}", info.owned_by);
println!("Created: {}", info.created);
}
Some(Command::Apikey(_)) => {
let builder = ApiKeyRequestBuilder::new(client.clone());
let info = builder.fetch_api_key_info().await?;
println!("ID: {}", info.api_key_id);
println!("Name: {}", info.name);
println!("Blocked: {}", info.api_key_blocked);
println!("Disabled: {}", info.api_key_disabled);
println!("Team: {}", info.team_id);
println!("ACLs: {}", info.acls.join(", "));
}
None => {
run_tui().await?;
}
}
Ok(())
}