use crate::traits::Message;
use chrono::{DateTime, Utc};
pub fn memory_score(
similarity: f32,
created_at: DateTime<Utc>,
recall_count: i32,
last_recalled: Option<DateTime<Utc>>,
) -> f32 {
let now = Utc::now();
let days_since_created = (now - created_at).num_hours() as f32 / 24.0;
let recency_decay = 1.0 / (1.0 + days_since_created * 0.1);
let recall_boost = 1.0 + (recall_count as f32 * 0.1).min(0.5);
let recall_recency = last_recalled
.map(|t| {
let days_since_recall = (now - t).num_hours() as f32 / 24.0;
1.0 / (1.0 + days_since_recall * 0.05)
})
.unwrap_or(1.0);
similarity * recency_decay * recall_boost * recall_recency
}
pub fn calculate_episode_importance(
message_count: i32,
has_errors: bool,
has_decisions: bool,
has_goals: bool,
emotional_intensity: f32, ) -> f32 {
let mut importance = 0.5;
if message_count > 20 {
importance += 0.2;
} else if message_count > 10 {
importance += 0.1;
}
if has_errors {
importance += 0.15;
}
if has_decisions {
importance += 0.1;
}
if has_goals {
importance += 0.1;
}
importance += emotional_intensity * 0.2;
importance.clamp(0.1, 1.0)
}
pub fn score_message(msg: &Message) -> f32 {
score_role_and_content(&msg.role, msg.content.as_deref())
}
pub fn score_turn(turn: &crate::events::ConversationTurn) -> f32 {
score_role_and_content(turn.role.as_str(), turn.content.as_deref())
}
fn score_role_and_content(role: &str, content: Option<&str>) -> f32 {
let mut score: f32 = 0.5;
match role {
"system" => return 0.0, "tool" => score = 0.3, "assistant" => score = 0.5,
"user" => score = 0.6, _ => {}
}
if let Some(content) = content {
let text = content.to_lowercase();
let len = content.len();
if len > 200 {
score += 0.2;
} else if len < 20 {
score -= 0.2;
}
if text.contains("important")
|| text.contains("remember")
|| text.contains("do not forget")
|| text.contains("don't forget")
|| text.contains("keep in mind")
|| text.contains("note that")
{
score += 0.3;
}
if text.contains('?')
|| text.starts_with("how ")
|| text.starts_with("what ")
|| text.starts_with("why ")
|| text.starts_with("where ")
|| text.starts_with("when ")
|| text.starts_with("can you ")
|| text.starts_with("could you ")
{
score += 0.1;
}
if text.contains("let's go with")
|| text.contains("i chose")
|| text.contains("i decided")
|| text.contains("we'll use")
|| text.contains("let's use")
|| text.contains("switch to")
|| text.contains("going with")
|| text.contains("the plan is")
{
score += 0.25;
}
if text.contains("actually")
|| text.contains("no, ")
|| text.contains("instead")
|| text.contains("i prefer")
|| text.contains("don't use")
|| text.contains("always use")
|| text.contains("never use")
{
score += 0.2;
}
if text.contains("http://")
|| text.contains("https://")
|| text.contains("github.com")
|| text.contains(".rs:")
|| text.contains(".ts:")
|| text.contains(".py:")
|| text.contains("~/")
|| text.contains("/src/")
|| text.contains("/home/")
{
score += 0.1;
}
if text.contains("```") {
score += 0.2;
}
if ((text.contains('{') && text.contains('}'))
|| (text.contains('[') && text.contains(']')))
&& len > 50
{
score += 0.1;
}
if len < 15
&& (text == "ok"
|| text == "okay"
|| text == "thanks"
|| text == "cool"
|| text == "got it"
|| text == "sure"
|| text == "yes"
|| text == "no"
|| text == "k"
|| text == "ty"
|| text == "thx"
|| text == "yep")
{
score -= 0.3;
}
}
score.clamp(0.1, 1.0)
}