aidale_core/
layer.rs

1//! Layer trait and abstractions.
2//!
3//! Inspired by OpenDAL's architecture, layers provide a composable way to wrap
4//! providers with cross-cutting concerns like logging, retry, caching, etc.
5
6use crate::error::AiError;
7use crate::provider::Provider;
8use crate::types::*;
9use async_trait::async_trait;
10use std::sync::Arc;
11
12/// Layer trait for wrapping providers.
13///
14/// Similar to OpenDAL's Layer, this trait allows composing providers with
15/// middleware-like functionality. Each layer wraps an inner provider and
16/// returns a new provider with enhanced capabilities.
17pub trait Layer<P: Provider> {
18    /// The type of the layered provider
19    type LayeredProvider: Provider;
20
21    /// Wrap the inner provider with this layer
22    fn layer(&self, inner: P) -> Self::LayeredProvider;
23}
24
25/// Helper trait for layered providers.
26///
27/// This trait provides default forwarding implementations for provider methods,
28/// similar to OpenDAL's LayeredProvider. Implementers only need to override
29/// the methods they want to intercept.
30#[async_trait]
31pub trait LayeredProvider: Sized + Provider {
32    /// The inner provider type
33    type Inner: Provider;
34
35    /// Get a reference to the inner provider
36    fn inner(&self) -> &Self::Inner;
37
38    /// Default implementation for info - forwards to inner
39    fn layered_info(&self) -> Arc<ProviderInfo> {
40        self.inner().info()
41    }
42
43    /// Default implementation for chat_completion - forwards to inner
44    async fn layered_chat_completion(
45        &self,
46        req: ChatCompletionRequest,
47    ) -> Result<ChatCompletionResponse, AiError> {
48        self.inner().chat_completion(req).await
49    }
50
51    /// Default implementation for stream_chat_completion - forwards to inner
52    async fn layered_stream_chat_completion(
53        &self,
54        req: ChatCompletionRequest,
55    ) -> Result<Box<crate::provider::ChatCompletionStream>, AiError> {
56        self.inner().stream_chat_completion(req).await
57    }
58}
59
60/// Macro to implement Provider trait by forwarding to LayeredProvider methods.
61///
62/// This reduces boilerplate for layered providers.
63#[macro_export]
64macro_rules! impl_layered_provider {
65    ($type:ty) => {
66        #[async_trait::async_trait]
67        impl $crate::provider::Provider for $type {
68            fn info(&self) -> std::sync::Arc<$crate::types::ProviderInfo> {
69                $crate::layer::LayeredProvider::layered_info(self)
70            }
71
72            async fn chat_completion(
73                &self,
74                req: $crate::types::ChatCompletionRequest,
75            ) -> Result<$crate::types::ChatCompletionResponse, $crate::error::AiError> {
76                $crate::layer::LayeredProvider::layered_chat_completion(self, req).await
77            }
78
79            async fn stream_chat_completion(
80                &self,
81                req: $crate::types::ChatCompletionRequest,
82            ) -> Result<Box<$crate::provider::ChatCompletionStream>, $crate::error::AiError> {
83                $crate::layer::LayeredProvider::layered_stream_chat_completion(self, req).await
84            }
85        }
86    };
87}