use serde::{Deserialize, Serialize};
use std::path::PathBuf;
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct SourceContext {
pub paths: Vec<PathBuf>,
pub snippets: Vec<SourceSnippet>,
pub total_tokens: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SourceSnippet {
pub path: PathBuf,
pub lines: Option<(usize, usize)>,
pub content: String,
pub tokens: usize,
}
impl SourceContext {
pub fn new() -> Self {
Self::default()
}
pub fn add_path(&mut self, path: PathBuf) {
self.paths.push(path);
}
pub fn add_snippet(&mut self, snippet: SourceSnippet) {
self.total_tokens += snippet.tokens;
self.snippets.push(snippet);
}
pub fn format_for_prompt(&self) -> String {
if self.snippets.is_empty() {
return String::new();
}
let mut output = String::new();
output.push_str("## Source Context (Genchi Genbutsu)\n\n");
output.push_str("The following source material must be referenced in your output:\n\n");
for snippet in &self.snippets {
output.push_str(&format!("### {}\n", snippet.path.display()));
if let Some((start, end)) = snippet.lines {
output.push_str(&format!("Lines {}-{}:\n", start, end));
}
output.push_str("```\n");
output.push_str(&snippet.content);
output.push_str("\n```\n\n");
}
output.push_str("**Requirement**: Quote or reference specific line numbers from the source material above.\n\n");
output
}
}