rustic-ai 0.1.0

A Rust-native agent framework with tool calling, streaming, and multi-provider support for OpenAI, Anthropic, Gemini, and Grok
Documentation
use std::sync::Arc;

use reqwest::Url;

use crate::model::{Model, ModelSettings};
use crate::providers::openai::{OpenAIChatCapabilities, OpenAIChatModel};
use crate::providers::{Provider, ProviderError};

#[derive(Clone, Debug)]
pub struct GrokProvider {
    api_key: String,
    base_url: Url,
}

impl GrokProvider {
    pub fn new(
        api_key: impl Into<String>,
        base_url: impl AsRef<str>,
    ) -> Result<Self, ProviderError> {
        let url = Url::parse(base_url.as_ref())
            .map_err(|_| ProviderError::InvalidModel(base_url.as_ref().to_string()))?;
        Ok(Self {
            api_key: api_key.into(),
            base_url: url,
        })
    }

    pub fn from_env() -> Result<Self, ProviderError> {
        let api_key = std::env::var("XAI_API_KEY")
            .or_else(|_| std::env::var("GROK_API_KEY"))
            .map_err(|_| ProviderError::MissingApiKey("grok".to_string()))?;
        Self::new(api_key, "https://api.x.ai/v1")
    }
}

impl Provider for GrokProvider {
    fn name(&self) -> &str {
        "grok"
    }

    fn model(&self, model: &str, settings: Option<ModelSettings>) -> Arc<dyn Model> {
        let capabilities = OpenAIChatCapabilities {
            supports_response_format: false,
            supports_parallel_tool_calls: true,
            reject_binary_images: true,
        };
        Arc::new(OpenAIChatModel::new_with_capabilities(
            model,
            self.api_key.clone(),
            self.base_url.clone(),
            settings,
            capabilities,
        ))
    }
}