use std::collections::BTreeMap;
use crate::schema::{AgentName, Mode};
pub fn melchior_prompt() -> &'static str {
include_str!("../prompts_md/melchior.md")
}
pub fn balthasar_prompt() -> &'static str {
include_str!("../prompts_md/balthasar.md")
}
pub fn caspar_prompt() -> &'static str {
include_str!("../prompts_md/caspar.md")
}
pub(crate) fn embedded_prompt_for(name: AgentName) -> &'static str {
match name {
AgentName::Melchior => melchior_prompt(),
AgentName::Balthasar => balthasar_prompt(),
AgentName::Caspar => caspar_prompt(),
}
}
pub(crate) fn lookup_prompt(
agent: AgentName,
mode: Mode,
overrides: &BTreeMap<(AgentName, Option<Mode>), String>,
) -> &str {
if let Some(s) = overrides.get(&(agent, Some(mode))) {
return s.as_str();
}
if let Some(s) = overrides.get(&(agent, None)) {
return s.as_str();
}
embedded_prompt_for(agent)
}
#[cfg(test)]
mod tests_v0_3 {
use super::*;
#[test]
fn test_melchior_prompt_is_non_empty() {
assert!(!melchior_prompt().is_empty());
}
#[test]
fn test_balthasar_prompt_is_non_empty() {
assert!(!balthasar_prompt().is_empty());
}
#[test]
fn test_caspar_prompt_is_non_empty() {
assert!(!caspar_prompt().is_empty());
}
#[test]
fn test_three_prompts_are_distinct() {
assert_ne!(melchior_prompt(), balthasar_prompt());
assert_ne!(balthasar_prompt(), caspar_prompt());
assert_ne!(melchior_prompt(), caspar_prompt());
}
#[test]
fn test_prompts_match_python_reference_sha256() {
use sha2::{Digest, Sha256};
let fixture = include_str!("../../tests/fixtures/magi_ref_prompts.sha256");
let mut expected: std::collections::HashMap<&str, &str> = std::collections::HashMap::new();
for line in fixture.lines() {
if line.starts_with('#') || line.trim().is_empty() {
continue;
}
let parts: Vec<&str> = line.splitn(2, " ").collect();
assert_eq!(parts.len(), 2, "bad fixture line: {line}");
expected.insert(parts[1].trim(), parts[0].trim());
}
for (filename, content) in [
("melchior.md", melchior_prompt()),
("balthasar.md", balthasar_prompt()),
("caspar.md", caspar_prompt()),
] {
let expected_hash = expected
.get(filename)
.unwrap_or_else(|| panic!("no fixture entry for {filename}"));
let actual_hash = format!("{:x}", Sha256::digest(content.as_bytes()));
assert_eq!(
&actual_hash, expected_hash,
"{filename} content drifted from Python reference"
);
}
}
}