x-ai 0.1.0

✨ A cli, tui, and sdk for interacting with the 𝕏-AI API
Documentation
// Copyright 2026 Mahmoud Harmouch.
//
// Licensed under the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Entry point for the `xai` binary.
//!
//! Run without a subcommand to launch the interactive TUI.
//! Run with a subcommand to perform a single operation and exit.
//!
//! Requires the `cli` feature:
//! ```shell
//! cargo run --features cli -- chat -t "Hello Grok"
//! ```

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(())
}
// Copyright 2026 Mahmoud Harmouch.
//
// Licensed under the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.