pub const EVOLUTION_DETECTION_PROMPT: &str = r#"Compare new information with existing memories and determine the relationship.
New information:
{new_content}
Existing memories:
{existing_list}
What is the relationship between the new information and existing memories?
- "update": New info replaces/corrects old (e.g., changed job, moved address)
- "extend": New info adds to old (e.g., more details, clarification)
- "derive": New info is conclusion from old (e.g., inference, deduction)
- "contradict": New info conflicts with old (e.g., disagreement, correction)
- "none": No significant relationship
Return JSON with this exact structure:
{"type": "update|extend|derive|contradict|none", "reason": "brief explanation", "related_id": "id of most related memory or null", "confidence": 0.0-1.0}
Only return the JSON, nothing else."#;
#[must_use]
pub fn build_detection_prompt(new_content: &str, existing_list: &str) -> String {
EVOLUTION_DETECTION_PROMPT
.replace("{new_content}", new_content)
.replace("{existing_list}", existing_list)
}
#[must_use]
pub fn format_entity_for_prompt(id: &str, name: &str, content: &str) -> String {
let content_preview = if content.len() > 200 {
format!("{}...", &content[..200])
} else {
content.to_string()
};
format!("[{}] {}: {}", id, name, content_preview)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_build_detection_prompt() {
let prompt = build_detection_prompt(
"Alice: Left Acme and joined StartupX",
"[entity-1] Alice: Works at Acme Corp",
);
assert!(prompt.contains("Left Acme and joined StartupX"));
assert!(prompt.contains("[entity-1] Alice: Works at Acme Corp"));
assert!(prompt.contains("What is the relationship"));
assert!(prompt.contains("JSON"));
}
#[test]
fn test_prompt_structure() {
let prompt = build_detection_prompt("test content", "test list");
assert!(prompt.contains("Compare new information"));
assert!(prompt.contains("New information:"));
assert!(prompt.contains("Existing memories:"));
assert!(prompt.contains("update"));
assert!(prompt.contains("extend"));
assert!(prompt.contains("derive"));
assert!(prompt.contains("contradict"));
assert!(prompt.contains("none"));
assert!(prompt.contains("Only return the JSON"));
}
#[test]
fn test_format_entity_for_prompt() {
let formatted = format_entity_for_prompt("id-123", "Alice", "Works at Acme Corp");
assert_eq!(formatted, "[id-123] Alice: Works at Acme Corp");
}
#[test]
fn test_format_entity_truncates_long_content() {
let long_content = "a".repeat(300);
let formatted = format_entity_for_prompt("id-123", "Test", &long_content);
assert!(formatted.len() < 300);
assert!(formatted.ends_with("..."));
assert!(formatted.starts_with("[id-123] Test: "));
}
#[test]
fn test_format_entity_short_content_unchanged() {
let short_content = "Short content";
let formatted = format_entity_for_prompt("id-1", "Name", short_content);
assert_eq!(formatted, "[id-1] Name: Short content");
assert!(!formatted.ends_with("..."));
}
}