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}