pub mod history;
pub mod prompt;
pub mod skills;
pub mod system;
pub use history::{Conversation, ConversationMeta, HistoryManager};
pub use prompt::PromptBuilder;
pub use skills::SkillsManager;
pub use system::SystemLoader;
use crate::error::Result;
use uuid::Uuid;
#[derive(Clone)]
pub struct RagContext {
pub history: HistoryManager,
pub skills: SkillsManager,
pub system: SystemLoader,
default_skills: Vec<String>,
}
impl RagContext {
pub fn new(default_skills: Vec<String>) -> Result<Self> {
Ok(Self {
history: HistoryManager::new()?,
skills: SkillsManager::new()?,
system: SystemLoader::new()?,
default_skills,
})
}
pub fn prepare(
&self,
chat_id: Option<Uuid>,
skill_names: &[String],
model: Option<String>,
provider: Option<String>,
) -> Result<(Conversation, PromptBuilder)> {
let merged_skills = merge_skills(&self.default_skills, skill_names);
let conversation =
self.history
.resolve_conversation(chat_id, model, provider, merged_skills)?;
let mut builder = PromptBuilder::new();
let system_content = self.system.load()?;
tracing::debug!(chars = system_content.len(), "prepare: loaded system.md");
builder.set_system(system_content);
if !conversation.meta.skills.is_empty() {
let loaded = self.skills.load_skills(&conversation.meta.skills)?;
for (name, content) in &loaded {
tracing::debug!(skill = %name, "prepare: loaded skill");
builder.add_skill(name, content);
}
}
Ok((conversation, builder))
}
}
fn merge_skills(defaults: &[String], session: &[String]) -> Vec<String> {
let mut merged = Vec::new();
for s in defaults.iter().chain(session.iter()) {
if !merged.contains(s) {
merged.push(s.clone());
}
}
merged
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn merge_skills_defaults_first_no_duplicates() {
let defaults = vec!["rules".to_string(), "coding".to_string()];
let session = vec!["coding".to_string(), "rust".to_string()];
let merged = merge_skills(&defaults, &session);
assert_eq!(merged, vec!["rules", "coding", "rust"]);
}
#[test]
fn merge_skills_empty_defaults() {
let merged = merge_skills(&[], &["rust".to_string()]);
assert_eq!(merged, vec!["rust"]);
}
#[test]
fn merge_skills_empty_session() {
let merged = merge_skills(&["rules".to_string()], &[]);
assert_eq!(merged, vec!["rules"]);
}
#[test]
fn merge_skills_deduplicates_within_defaults() {
let defaults = vec!["rules".to_string(), "rules".to_string()];
let merged = merge_skills(&defaults, &[]);
assert_eq!(merged, vec!["rules"]);
}
}