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}