use rsclaw::agent::memory::{MemDocTier, MemoryDoc};
#[test]
fn tier_promotion_returns_true_on_first_core() {
let mut doc = MemoryDoc {
id: "d1".to_owned(),
scope: "agent:test".to_owned(),
kind: "note".to_owned(),
text: "test".to_owned(),
vector: vec![],
created_at: 0,
accessed_at: 0,
access_count: 10,
importance: 0.85,
tier: MemDocTier::Working,
abstract_text: None,
overview_text: None,
tags: vec![],
pinned: false,
};
assert!(doc.evaluate_tier_transition());
assert_eq!(doc.tier, MemDocTier::Core);
assert!(!doc.evaluate_tier_transition());
}
#[test]
fn tier_promotion_via_high_access_alone() {
let mut doc = MemoryDoc {
id: "frequent".to_owned(),
scope: "agent:test".to_owned(),
kind: "note".to_owned(),
text: "broadly relevant".to_owned(),
vector: vec![],
created_at: 0,
accessed_at: 0,
access_count: 15, importance: 0.5, tier: MemDocTier::Working,
abstract_text: None,
overview_text: None,
tags: vec![],
pinned: false,
};
assert!(doc.evaluate_tier_transition());
assert_eq!(doc.tier, MemDocTier::Core);
}
#[test]
fn tier_promotion_via_high_importance_alone() {
let mut doc = MemoryDoc {
id: "important".to_owned(),
scope: "agent:test".to_owned(),
kind: "note".to_owned(),
text: "strong positive feedback".to_owned(),
vector: vec![],
created_at: 0,
accessed_at: 0,
access_count: 2, importance: 0.95, tier: MemDocTier::Working,
abstract_text: None,
overview_text: None,
tags: vec![],
pinned: false,
};
assert!(doc.evaluate_tier_transition());
assert_eq!(doc.tier, MemDocTier::Core);
}
#[test]
fn tier_no_promotion_when_below_all_paths() {
let mut doc = MemoryDoc {
id: "marginal".to_owned(),
scope: "agent:test".to_owned(),
kind: "note".to_owned(),
text: "not enough yet".to_owned(),
vector: vec![],
created_at: 0,
accessed_at: 0,
access_count: 4, importance: 0.85, tier: MemDocTier::Working,
abstract_text: None,
overview_text: None,
tags: vec![],
pinned: false,
};
assert!(!doc.evaluate_tier_transition());
assert_ne!(doc.tier, MemDocTier::Core);
}
#[test]
fn tier_demotion_does_not_return_true() {
let mut doc = MemoryDoc {
id: "d2".to_owned(),
scope: "agent:test".to_owned(),
kind: "note".to_owned(),
text: "old".to_owned(),
vector: vec![],
created_at: 0, accessed_at: 0,
access_count: 0,
importance: 0.1,
tier: MemDocTier::Working,
abstract_text: None,
overview_text: None,
tags: vec![],
pinned: false,
};
assert!(!doc.evaluate_tier_transition());
assert_eq!(doc.tier, MemDocTier::Peripheral);
}
use rsclaw::heartbeat::{parse_heartbeat_md, HeartbeatType};
#[test]
fn parse_meditate_type() {
let raw = "---\nevery: 6h\ntype: meditate\n---\nRun memory maintenance.";
let spec = parse_heartbeat_md(raw).expect("parse meditate heartbeat");
assert_eq!(spec.spec_type, HeartbeatType::Meditate);
assert!(spec.content.contains("memory maintenance"));
}
#[test]
fn parse_meditation_type_alias() {
let raw = "---\nevery: 4h\ntype: meditation\n---\nCleanup.";
let spec = parse_heartbeat_md(raw).expect("parse meditation heartbeat");
assert_eq!(spec.spec_type, HeartbeatType::Meditate);
}
#[test]
fn parse_default_type_is_message() {
let raw = "---\nevery: 30m\n---\nCheck health.";
let spec = parse_heartbeat_md(raw).expect("parse default heartbeat");
assert_eq!(spec.spec_type, HeartbeatType::Message);
}
use rsclaw::skill::crystallizer::slugify;
#[test]
fn slugify_basic() {
assert_eq!(slugify("Web Search Pattern"), "web-search-pattern");
}
#[test]
fn slugify_special_chars() {
assert_eq!(slugify("file/download (v2)"), "file-download-v2");
}
#[test]
fn slugify_already_clean() {
assert_eq!(slugify("my-skill"), "my-skill");
}
#[test]
fn slugify_empty() {
assert_eq!(slugify(""), "unnamed-skill");
}
use rsclaw::skill::crystallizer::{build_distill_prompt, write_skill};
#[test]
fn build_distill_prompt_contains_cluster_texts() {
let docs: Vec<MemoryDoc> = (0..3)
.map(|i| MemoryDoc {
id: format!("c{i}"),
scope: "agent:test".to_owned(),
kind: "note".to_owned(),
text: format!("Memory about topic X, variant {i}"),
vector: vec![],
created_at: 0,
accessed_at: 0,
access_count: 12,
importance: 0.9,
tier: MemDocTier::Core,
abstract_text: None,
overview_text: None,
tags: vec![],
pinned: false,
})
.collect();
let prompt = build_distill_prompt(&docs);
assert!(prompt.contains("variant 0"), "prompt missing variant 0");
assert!(prompt.contains("variant 1"), "prompt missing variant 1");
assert!(prompt.contains("variant 2"), "prompt missing variant 2");
assert!(
prompt.contains("SKILL.md") || prompt.contains("skill"),
"prompt should mention skill format"
);
}
#[test]
fn write_skill_creates_file() {
let dir = std::env::temp_dir().join("rsclaw-test-skills");
let _ = std::fs::remove_dir_all(&dir);
let content = "---\nname: test-skill\ndescription: A test\nversion: 1.0.0\n---\nStep 1: do something";
let path = write_skill(&dir, "test-skill", content).expect("write_skill");
assert!(path.exists(), "SKILL.md should exist");
let read = std::fs::read_to_string(&path).expect("read skill");
assert!(read.contains("test-skill"), "content should contain name");
assert!(read.contains("Step 1"), "content should contain steps");
let _ = std::fs::remove_dir_all(&dir);
}
use rsclaw::heartbeat::meditation::MeditationConfig;
#[test]
fn meditation_config_defaults() {
let cfg = MeditationConfig::default();
assert!((cfg.dedup_threshold - 0.92).abs() < 0.01);
assert_eq!(cfg.batch_size, 50);
assert_eq!(cfg.crystallized_ttl_days, 7);
}