reka 0.1.0

Async Rust SDK for the Reka API.
Documentation
use std::sync::Arc;

use reqwest::Method;

use crate::chat::ChatClient;
use crate::config::{ClientConfig, ServiceBase};
use crate::error::{RekaError, Result};
use crate::models::ModelsClient;
use crate::research::ResearchClient;
use crate::transport::http::HttpTransport;
use crate::transport::request::RequestBuilder;
use crate::vision::VisionClient;

/// Entry point for the typed Reka SDK.
///
/// Create a client with [`Client::from_env`], [`Client::new`], or
/// [`Client::with_config`], then access service-specific handles such as
/// [`Client::chat`] or [`Client::vision`].
///
/// ```no_run
/// use reka::{ChatMessage, Client, CreateChatCompletionArgs, ModelId};
///
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), reka::RekaError> {
/// let client = Client::from_env()?;
/// let args = CreateChatCompletionArgs::new(
///     ModelId::flash(),
///     vec![ChatMessage::user("Say hello in one sentence.")],
/// );
///
/// let _response = client.chat().create(&args).await?;
/// # Ok(())
/// # }
/// ```
#[derive(Clone)]
pub struct Client {
    inner: Arc<ClientInner>,
}

struct ClientInner {
    config: ClientConfig,
    transport: HttpTransport,
}

impl Client {
    /// Creates a client from an API key.
    pub fn new(api_key: impl Into<String>) -> Result<Self> {
        Self::with_config(ClientConfig::builder(api_key).build()?)
    }

    /// Creates a client from `REKA_API_KEY` and related `REKA_*` environment
    /// variables.
    pub fn from_env() -> Result<Self> {
        Self::with_config(ClientConfig::from_env()?)
    }

    /// Creates a client from an explicit [`ClientConfig`].
    pub fn with_config(config: ClientConfig) -> Result<Self> {
        let transport = HttpTransport::new(&config)?;
        Ok(Self {
            inner: Arc::new(ClientInner { config, transport }),
        })
    }

    /// Returns the active client configuration.
    pub fn config(&self) -> &ClientConfig {
        &self.inner.config
    }

    /// Returns a handle for the models API.
    pub fn models(&self) -> ModelsClient {
        ModelsClient::new(self.clone())
    }

    /// Returns a handle for the chat completions API.
    pub fn chat(&self) -> ChatClient {
        ChatClient::new(self.clone())
    }

    /// Returns a handle for the research API.
    pub fn research(&self) -> ResearchClient {
        ResearchClient::new(self.clone())
    }

    /// Returns a handle for the vision API.
    pub fn vision(&self) -> VisionClient {
        VisionClient::new(self.clone())
    }

    pub(crate) fn request(
        &self,
        service: ServiceBase,
        method: Method,
        path: impl Into<String>,
    ) -> RequestBuilder {
        self.inner
            .transport
            .request(&self.inner.config, service, method, path)
    }

    pub(crate) fn map_transport_error(error: reqwest::Error) -> RekaError {
        RekaError::Transport(error)
    }
}