rustglm 1.0.0

Production-oriented async Rust SDK for Zhipu GLM, Realtime, Batch, RAG, and MCP
Documentation
use std::pin::Pin;

use async_trait::async_trait;
use futures_util::Stream;

use crate::{ChatCompletionChunk, ChatCompletionRequest, ChatCompletionResponse, Result};

pub type ChatStream = Pin<Box<dyn Stream<Item = Result<ChatCompletionChunk>> + Send>>;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ProviderCapabilities {
    pub streaming: bool,
    pub multimodal: bool,
    pub tools: bool,
    pub embeddings: bool,
    pub images: bool,
    pub audio: bool,
    pub video: bool,
    pub files: bool,
    pub batches: bool,
    pub realtime: bool,
}

impl ProviderCapabilities {
    pub const fn zhipu() -> Self {
        Self {
            streaming: true,
            multimodal: true,
            tools: true,
            embeddings: true,
            images: true,
            audio: true,
            video: true,
            files: true,
            batches: true,
            realtime: cfg!(feature = "realtime"),
        }
    }

    pub const fn openai_compatible() -> Self {
        Self {
            streaming: true,
            multimodal: true,
            tools: true,
            embeddings: false,
            images: false,
            audio: false,
            video: false,
            files: false,
            batches: false,
            realtime: false,
        }
    }
}

#[async_trait]
pub trait ChatProvider: Send + Sync {
    fn name(&self) -> &str;
    fn capabilities(&self) -> ProviderCapabilities;
    async fn complete(&self, request: ChatCompletionRequest) -> Result<ChatCompletionResponse>;
    async fn stream(&self, request: ChatCompletionRequest) -> Result<ChatStream>;
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn zhipu_capabilities_are_complete() {
        let value = ProviderCapabilities::zhipu();
        assert!(value.streaming);
        assert!(value.multimodal);
        assert!(value.tools);
        assert!(value.embeddings);
        assert!(value.images);
        assert!(value.audio);
        assert!(value.video);
        assert!(value.files);
        assert!(value.batches);
        assert_eq!(value.realtime, cfg!(feature = "realtime"));
    }

    #[test]
    fn compatible_capabilities_do_not_overclaim() {
        let value = ProviderCapabilities::openai_compatible();
        assert!(value.streaming);
        assert!(value.multimodal);
        assert!(value.tools);
        assert!(!value.embeddings);
        assert!(!value.images);
        assert!(!value.audio);
        assert!(!value.video);
        assert!(!value.files);
        assert!(!value.batches);
        assert!(!value.realtime);
    }
}