1use serde::{Deserialize, Serialize};
2
3use super::retrieval::{RetrieveRequest, RetrieveResult};
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct RagRequest {
10 pub query: String,
12 pub system_prompt: Option<String>,
14 pub history: Vec<ChatMessage>,
16 pub retrieve_config: RetrieveRequest,
18 pub generation: RagGenerationConfig,
20 pub context_config: Option<ContextConfig>,
22 pub prompt_template: Option<String>,
24 pub options: RequestOptions,
26}
27
28impl RagRequest {
29 pub fn builder(query: impl Into<String>) -> RagRequestBuilder {
31 RagRequestBuilder {
32 query: query.into(),
33 system_prompt: None,
34 history: vec![],
35 retrieve_config: RetrieveRequest::builder("").build(),
36 generation: RagGenerationConfig::default(),
37 context_config: None,
38 prompt_template: None,
39 options: RequestOptions::default(),
40 }
41 }
42}
43
44pub struct RagRequestBuilder {
46 query: String,
47 system_prompt: Option<String>,
48 history: Vec<ChatMessage>,
49 retrieve_config: RetrieveRequest,
50 generation: RagGenerationConfig,
51 context_config: Option<ContextConfig>,
52 prompt_template: Option<String>,
53 options: RequestOptions,
54}
55
56impl RagRequestBuilder {
57 pub fn system_prompt(mut self, sp: impl Into<String>) -> Self {
59 self.system_prompt = Some(sp.into());
60 self
61 }
62
63 pub fn history(mut self, h: Vec<ChatMessage>) -> Self {
65 self.history = h;
66 self
67 }
68
69 pub fn retrieve_config(mut self, rc: RetrieveRequest) -> Self {
71 self.retrieve_config = rc;
72 self
73 }
74
75 pub fn generation(mut self, g: RagGenerationConfig) -> Self {
77 self.generation = g;
78 self
79 }
80
81 pub fn context_config(mut self, cc: ContextConfig) -> Self {
83 self.context_config = Some(cc);
84 self
85 }
86
87 pub fn prompt_template(mut self, pt: impl Into<String>) -> Self {
89 self.prompt_template = Some(pt.into());
90 self
91 }
92
93 pub fn options(mut self, opts: RequestOptions) -> Self {
95 self.options = opts;
96 self
97 }
98
99 pub fn build(self) -> RagRequest {
101 RagRequest {
102 query: self.query,
103 system_prompt: self.system_prompt,
104 history: self.history,
105 retrieve_config: self.retrieve_config,
106 generation: self.generation,
107 context_config: self.context_config,
108 prompt_template: self.prompt_template,
109 options: self.options,
110 }
111 }
112}
113
114#[derive(Debug, Clone, Serialize, Deserialize)]
118pub struct ChatMessage {
119 pub role: ChatRole,
121 pub content: String,
123}
124
125#[derive(Debug, Clone, Serialize, Deserialize)]
127pub enum ChatRole {
128 System,
130 User,
132 Assistant,
134}
135
136#[derive(Debug, Clone, Serialize, Deserialize, Default)]
140pub struct RequestOptions {
141 pub namespace: Option<String>,
143 pub timeout_ms: Option<u64>,
145 pub retry_count: Option<u32>,
147 pub stream: bool,
149}
150
151#[derive(Debug, Clone, Serialize, Deserialize)]
155pub struct RagGenerationConfig {
156 pub max_context_tokens: usize,
158 pub model: Option<String>,
160 pub temperature: Option<f32>,
162 pub max_output_tokens: Option<usize>,
164 pub stream: bool,
166}
167
168impl Default for RagGenerationConfig {
169 fn default() -> Self {
170 Self {
171 max_context_tokens: 4096,
172 model: None,
173 temperature: Some(0.7),
174 max_output_tokens: Some(1024),
175 stream: false,
176 }
177 }
178}
179
180#[derive(Debug, Clone, Serialize, Deserialize)]
184pub struct ContextConfig {
185 pub max_context_tokens: usize,
187 pub system_prompt_reserve: usize,
189 pub query_reserve: usize,
191 pub output_reserve: usize,
193 pub min_chunk_overlap: usize,
195 pub citation_format: CitationFormat,
197}
198
199impl Default for ContextConfig {
200 fn default() -> Self {
201 Self {
202 max_context_tokens: 4096,
203 system_prompt_reserve: 256,
204 query_reserve: 128,
205 output_reserve: 512,
206 min_chunk_overlap: 50,
207 citation_format: CitationFormat::Numeric,
208 }
209 }
210}
211
212#[derive(Debug, Clone, Serialize, Deserialize)]
214pub enum CitationFormat {
215 Numeric,
217 ChunkId,
219 SourceName,
221}
222
223#[derive(Debug, Clone, Serialize, Deserialize)]
227pub struct RagResponse {
228 pub answer: String,
230 pub citations: Vec<Citation>,
232 pub usage: RagTokenUsage,
234 pub retrieve_stats: RetrieveResult,
236 pub total_latency_ms: u64,
238 pub model: Option<String>,
240}
241
242#[derive(Debug, Clone, Serialize, Deserialize)]
246pub struct Citation {
247 pub index: usize,
249 pub chunk_id: String,
251 pub content: String,
253 pub document_title: Option<String>,
255 pub score: f32,
257 pub channel: String,
259}
260
261#[derive(Debug, Clone, Serialize, Deserialize, Default)]
265pub struct RagTokenUsage {
266 pub context_tokens: usize,
268 pub prompt_tokens: usize,
270 pub completion_tokens: usize,
272 pub total_tokens: usize,
274 pub chunks_used: usize,
276 pub chunks_dropped: usize,
278}
279
280#[derive(Debug, Clone, Serialize, Deserialize)]
284pub struct PromptTemplate {
285 pub name: String,
287 pub system: String,
289 pub user_template: String,
291 pub context_prefix: String,
293 pub chunk_format: String,
295 pub context_suffix: String,
297 pub citation_instruction: String,
299}
300
301impl PromptTemplate {
302 pub fn default_qa() -> Self {
304 Self {
305 name: "default_qa".into(),
306 system: "You are a helpful assistant. Answer the user's question based on the provided context.".into(),
307 user_template: "Question: {query}\n\nContext:\n{context}\n\nAnswer:".into(),
308 context_prefix: "Relevant information:\n".into(),
309 chunk_format: "[{index}] {content}\n".into(),
310 context_suffix: "\n".into(),
311 citation_instruction: "Please cite sources using [N] notation when referencing the context.".into(),
312 }
313 }
314
315 pub fn render(&self, query: &str, context: &str) -> String {
317 self.user_template.replace("{query}", query).replace("{context}", context)
318 }
319}
320
321#[derive(Debug, Clone, Serialize, Deserialize)]
325#[serde(tag = "type")]
326pub enum RagStreamEvent {
327 RetrievalStarted {
329 channel_count: usize,
331 },
332 ChannelDone {
334 channel: String,
336 hits: usize,
338 latency_ms: u64,
340 },
341 GenerationStarted {
343 context_chunks: usize,
345 context_tokens: usize,
347 },
348 ContentDelta {
350 delta: String,
352 },
353 Citation {
355 chunk_id: String,
357 index: usize,
359 },
360 Done {
362 total_latency_ms: u64,
364 citations: Vec<Citation>,
366 usage: RagTokenUsage,
368 },
369}
370
371#[derive(Debug, Clone, Serialize, Deserialize)]
375pub struct BuiltContext {
376 pub context_text: String,
378 pub citations: Vec<Citation>,
380 pub chunks_used: usize,
382 pub chunks_dropped: usize,
384 pub tokens_used: usize,
386}