latchlm_core/
lib.rs

1// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
2// If a copy of the MPL was not distributed with this file, You can obtain one at
3// https://mozilla.org/MPL/2.0/.
4
5//! # LatchLM Core
6//!
7//! Core traits and types for the LatchLM ecosystem.
8//!
9//! This crate provides the foundation for the LatchLM ecosystem by defining
10//! the core abstractions used across all provider implementations.
11
12pub mod error;
13pub use error::*;
14
15use serde::{Deserialize, Serialize};
16use std::{future::Future, pin::Pin, sync::Arc};
17
18/// A `Future` type used by the `AiProvider` trait.
19///
20/// This type alias represents a boxed, pinned future that is `Send` and `'static`,
21/// which allows to be returned from async traits.
22pub type BoxFuture<T> = Pin<Box<dyn Future<Output = T> + Send + 'static>>;
23
24/// A marker trait representing a specific AI model for a provider.
25///
26/// Implementors of this trait represent specific model variants supported by an LLM provider.
27/// Each model must be convertible to a string identifier that can be used in API requests.
28///
29/// # Example
30/// ```
31/// use latchlm_core::AiModel;
32///
33/// pub enum MyModel {
34///     Variant1,
35///     Variant2,
36/// }
37///
38/// impl AsRef<str> for MyModel {
39///     fn as_ref(&self) -> &str {
40///         match self {
41///             MyModel::Variant1 => "mymodel-variant-1",
42///             MyModel::Variant2 => "mymodel-variant-2",
43///         }
44///     }
45/// }
46///
47/// impl AiModel for MyModel {}
48/// ```
49pub trait AiModel: AsRef<str> + Send + Sync {}
50
51/// A unique identifier for an LLM model.
52#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
53pub struct ModelId {
54    /// The technical identifier used in API requests
55    pub id: String,
56    /// A human-readable name
57    pub name: String,
58}
59
60impl std::fmt::Display for ModelId {
61    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62        write!(f, "{}", self.name)
63    }
64}
65
66/// A request for an LLM.
67#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
68pub struct AiRequest {
69    /// The input text to be processed by the model
70    pub text: String,
71}
72
73/// Response from an LLM API provider.
74#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
75pub struct AiResponse {
76    /// The text response
77    pub text: String,
78}
79
80/// A trait representing an LLM API provider.
81///
82/// Implementors of this trait provide the functionality to interact with specific
83/// LLM API providers through a unified interface.
84///
85/// Blanket implementations are provided for `&T`, `&mut T`, `Box<T>` and `Arc<T>`
86/// where `T: AiProvider`.
87pub trait AiProvider: Send + Sync {
88    /// Sends a message to the specified model and returns the AI's response.
89    ///
90    /// # Arguments
91    ///
92    /// * `model` - The identifier of the model to use.
93    /// * `request` - The request to send to the model.
94    ///
95    /// # Returns
96    ///
97    /// A future yielding either a `Response` or an `Error`
98    ///
99    /// # Errors
100    ///
101    /// Returns an `Error` if the request fails, the response status is not successful,
102    /// or if the response cannot be parsed.
103    fn send_request(
104        &self,
105        model: &dyn AiModel,
106        request: AiRequest,
107    ) -> BoxFuture<Result<AiResponse>>;
108}
109
110impl<T> AiProvider for &T
111where
112    T: AiProvider + ?Sized,
113{
114    fn send_request(
115        &self,
116        model: &dyn AiModel,
117        request: AiRequest,
118    ) -> BoxFuture<Result<AiResponse>> {
119        (**self).send_request(model, request)
120    }
121}
122
123impl<T> AiProvider for &mut T
124where
125    T: AiProvider + ?Sized,
126{
127    fn send_request(
128        &self,
129        model: &dyn AiModel,
130        request: AiRequest,
131    ) -> BoxFuture<Result<AiResponse>> {
132        (**self).send_request(model, request)
133    }
134}
135
136impl<T> AiProvider for Box<T>
137where
138    T: AiProvider + ?Sized,
139{
140    fn send_request(
141        &self,
142        model: &dyn AiModel,
143        request: AiRequest,
144    ) -> BoxFuture<Result<AiResponse>> {
145        (**self).send_request(model, request)
146    }
147}
148
149impl<T> AiProvider for Arc<T>
150where
151    T: AiProvider + ?Sized,
152{
153    fn send_request(
154        &self,
155        model: &dyn AiModel,
156        request: AiRequest,
157    ) -> BoxFuture<Result<AiResponse>> {
158        (**self).send_request(model, request)
159    }
160}