alith_core/
chat.rs

1use alith_interface::requests::completion::ToolDefinition;
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4use std::error::Error;
5
6use crate::store::DocumentId;
7
8/// A trait representing a prompt-based interaction mechanism.
9///
10/// This trait defines the behavior of components that process user prompts
11/// and return responses asynchronously.
12///
13/// # Associated Types
14/// - `PromptError`: Represents errors that may occur during prompt processing.
15///
16/// # Requirements
17/// Implementors of this trait must ensure thread safety (`Send` and `Sync`)
18/// and provide an asynchronous implementation for the `prompt` method.
19pub trait Prompt: Send + Sync {
20    /// The error type associated with the `prompt` operation.
21    type PromptError: Error + Send + Sync;
22
23    /// Processes the given prompt and returns a response asynchronously.
24    ///
25    /// # Arguments
26    /// - `prompt`: The input string provided by the user.
27    ///
28    /// # Returns
29    /// A future that resolves to either:
30    /// - `Ok(String)`: The generated response as a string.
31    /// - `Err(Self::PromptError)`: An error that occurred during prompt processing.
32    fn prompt(
33        &self,
34        prompt: &str,
35    ) -> impl std::future::Future<Output = Result<String, Self::PromptError>> + Send;
36}
37
38#[derive(Clone, Debug, Deserialize, Serialize)]
39pub struct Message {
40    /// "system", "user", or "assistant"
41    pub role: String,
42    pub content: String,
43}
44
45/// Represents a document with an ID, text, and additional properties.
46#[derive(Clone, Debug, Deserialize, Serialize)]
47pub struct Document {
48    /// The unique identifier of the document.
49    pub id: DocumentId,
50    /// The text content of the document.
51    pub text: String,
52    /// Additional properties associated with the document, represented as key-value pairs.
53    #[serde(flatten)]
54    pub additional_props: HashMap<String, String>,
55}
56
57impl std::fmt::Display for Document {
58    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59        write!(
60            f,
61            concat!("<document id: {}>\n", "{}\n", "</document>\n"),
62            self.id.0,
63            if self.additional_props.is_empty() {
64                self.text.clone()
65            } else {
66                let mut sorted_props = self.additional_props.iter().collect::<Vec<_>>();
67                sorted_props.sort_by(|a, b| a.0.cmp(b.0));
68                let metadata = sorted_props
69                    .iter()
70                    .map(|(k, v)| format!("{}: {:?}", k, v))
71                    .collect::<Vec<_>>()
72                    .join(" ");
73                format!("<metadata {} />\n{}", metadata, self.text)
74            }
75        )
76    }
77}
78
79/// Represents a request sent to a language model for generating a completion response.
80///
81/// This struct provides a flexible interface to configure the language model's behavior
82/// and enhance its outputs with additional tools, documents, and contextual information.
83/// It is suited for a wide range of use cases, from simple prompt completions to
84/// advanced multi-turn interactions or tool-augmented tasks.
85#[derive(Debug, Clone)]
86pub struct Request {
87    /// The user-provided input text that the language model must complete or respond to.
88    ///
89    /// This is the primary query or message that serves as the basis for the model's response.
90    pub prompt: String,
91
92    /// A system-defined preamble to guide the behavior and tone of the model.
93    ///
94    /// Use this field to provide specific instructions to the model, such as role-playing as
95    /// an expert, adhering to a formal tone, or aligning responses with certain principles.
96    pub preamble: String,
97
98    /// A collection of knowledge sources available for enriching the request prompt.
99    ///
100    /// These knowledge sources are represented as `Box<dyn Knowledge>` objects,
101    /// which implement the `Knowledge` trait. Each knowledge source can process
102    /// the input prompt and return additional contextual or enriched information.
103    pub knowledges: Vec<String>,
104
105    /// A sequence of previous messages exchanged in the conversation.
106    ///
107    /// This provides context for multi-turn interactions, enabling the model to maintain
108    /// coherence and relevance across turns.
109    pub history: Vec<Message>,
110
111    /// Optional: Defines the maximum number of tokens allowed for the generated response.
112    ///
113    /// When set, this value restricts the length of the model's output. If not provided,
114    /// the system may use a default or determine the length dynamically.
115    pub max_tokens: Option<usize>,
116
117    /// Optional: Controls the randomness of the text generation process.
118    ///
119    /// Higher values (e.g., 1.0) result in more creative and diverse responses, while lower
120    /// values (e.g., 0.2) make the output more focused and deterministic. If `None`, the system
121    /// uses a default temperature.
122    pub temperature: Option<f32>,
123
124    /// A collection of tools available for tool-based interactions with the model.
125    ///
126    /// Tools are external systems, APIs, or utilities that the model can invoke to perform
127    /// specific tasks or enhance its responses.
128    pub tools: Vec<ToolDefinition>,
129
130    /// A collection of documents that provide context or background information for the model.
131    ///
132    /// These documents can be used by the model to generate more accurate and informed responses.
133    /// Examples include research papers, policy documents, or reference materials.
134    pub documents: Vec<Document>,
135}
136
137impl Request {
138    /// Constructs a new `Request` with the given prompt and preamble.
139    ///
140    /// # Arguments
141    /// - `prompt`: A string representing the user's input prompt.
142    /// - `preamble`: A string that defines the system preamble to guide the model.
143    ///
144    /// # Returns
145    /// A new instance of the `Request` struct.
146    pub fn new(prompt: String, preamble: String) -> Self {
147        Self {
148            prompt,
149            preamble,
150            knowledges: Vec::new(),
151            history: Vec::new(),
152            max_tokens: None,
153            temperature: None,
154            tools: Vec::new(),
155            documents: Vec::new(),
156        }
157    }
158
159    /// Constructs a prompt string that includes the context from the attached documents.
160    ///
161    /// # Returns
162    /// A string containing the formatted prompt with document attachments, if any.
163    pub(crate) fn prompt_with_context(&self, prompt: String) -> String {
164        if !self.documents.is_empty() {
165            format!(
166                "<attachments>\n{}</attachments>\n\n{}",
167                self.documents
168                    .iter()
169                    .map(|doc| doc.to_string())
170                    .collect::<Vec<_>>()
171                    .join(""),
172                prompt
173            )
174        } else {
175            prompt.clone()
176        }
177    }
178}
179
180/// A trait for extracting the content from a language model's response.
181pub trait ResponseContent {
182    /// Retrieves the main content from the response.
183    ///
184    /// # Returns
185    /// A string containing the text content of the response.
186    fn content(&self) -> String;
187}
188
189/// A trait for extracting tool-based calls from a language model's response.
190pub trait ResponseToolCalls {
191    /// Extracts tool calls from the response.
192    ///
193    /// # Returns
194    /// A vector of `ToolCall` objects representing tool-related interactions.
195    fn toolcalls(&self) -> Vec<ToolCall>;
196}
197
198/// Represents a call to a specific tool in a response.
199pub struct ToolCall {
200    /// The unique identifier for the tool call.
201    pub id: String,
202    /// The type of the tool call.
203    pub r#type: String,
204    /// The function being called, along with its name and arguments.
205    pub function: CallFunction,
206}
207
208/// Represents a callable function within a tool interaction.
209pub struct CallFunction {
210    /// The name of the function being invoked.
211    pub name: String,
212    /// The arguments provided to the function as a string.
213    pub arguments: String,
214}
215
216/// A trait defining the behavior of a completion engine.
217///
218/// This trait is used by components that handle requests for text generation
219/// (or similar completions) and generate responses asynchronously.
220///
221/// # Associated Types
222/// - `Response`: The specific type of the response generated by the completion engine.
223pub trait Completion {
224    /// The type of response returned by the `completion` method.
225    type Response: Send + Sync + ResponseContent + ResponseToolCalls;
226
227    /// Processes a `Request` and returns the generated response asynchronously.
228    ///
229    /// # Arguments
230    /// - `request`: The request object containing the prompt and additional configuration.
231    ///
232    /// # Returns
233    /// A future that resolves to either:
234    /// - `Ok(Self::Response)`: The generated response.
235    /// - `Err(CompletionError)`: An error encountered during the request processing.
236    fn completion(
237        &mut self,
238        request: Request,
239    ) -> impl std::future::Future<Output = Result<Self::Response, CompletionError>>;
240}
241
242/// An enumeration of possible errors that may occur during completion operations.
243#[derive(Debug, thiserror::Error)]
244pub enum CompletionError {
245    /// A generic completion error.
246    ///
247    /// # Details
248    /// - The error includes a message describing the cause of the failure.
249    #[error("A normal completion error occurred: {0}")]
250    Normal(String),
251    #[error("An inference error occurred: {0}")]
252    Inference(String),
253}