use crate::agent::messages::Role;
use crate::memory::config::MemoryConfig;
use crate::memory::MemoryKind;
#[allow(dead_code)]
pub fn assign_salience(kind: MemoryKind, text: &str, role: Role, cfg: &MemoryConfig) -> f64 {
if kind == MemoryKind::Preference {
return cfg.preference_salience.clamp(0.0, 1.0);
}
let mut s = cfg.default_salience;
let text_lower = text.to_lowercase();
let markers_lower: Vec<String> = cfg
.salience_markers
.iter()
.map(|m| m.to_lowercase())
.collect();
if markers_lower
.iter()
.any(|ml| text_lower.contains(ml.as_str()))
{
s = s.max(cfg.protect_salience_threshold);
}
if role == Role::User {
s += 0.05_f64;
}
s.clamp(0.0, 1.0)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::agent::messages::Role;
use crate::memory::config::MemoryConfig;
use crate::memory::MemoryKind;
#[test]
fn test_salience_is_deterministic_and_preference_is_protected() {
let cfg = MemoryConfig::default();
let s1 = assign_salience(MemoryKind::Episodic, "note the budget", Role::User, &cfg);
let s2 = assign_salience(MemoryKind::Episodic, "note the budget", Role::User, &cfg);
assert_eq!(s1, s2); assert!((0.0..=1.0).contains(&s1));
let p = assign_salience(MemoryKind::Preference, "always use rust", Role::User, &cfg);
assert!(p >= cfg.protect_salience_threshold); }
#[test]
fn test_preference_marker_lifts_episodic_to_protected_tier() {
let cfg = MemoryConfig {
salience_markers: vec!["prefer".into(), "always".into()],
..MemoryConfig::default()
};
let s = assign_salience(
MemoryKind::Episodic,
"I always prefer dark mode",
Role::User,
&cfg,
);
assert!(s >= cfg.protect_salience_threshold);
}
#[test]
fn test_plain_episodic_uses_default_salience_floor() {
let cfg = MemoryConfig::default();
let s = assign_salience(
MemoryKind::Episodic,
"the sky is blue",
Role::Assistant,
&cfg,
);
assert!(s >= cfg.default_salience && s < cfg.protect_salience_threshold);
}
}