#[tokio::test]
async fn test_same_channel_fact_recall() {
let harness = setup_test_agent(MockProvider::new()).await.unwrap();
harness
.state
.upsert_fact(
"project",
"framework",
"NextJS with TypeScript",
"user",
Some("slack:C_ABC"),
crate::types::FactPrivacy::Channel,
)
.await
.unwrap();
harness
.agent
.handle_message(
"same_ch_session",
"what framework are we using?",
None,
UserRole::Owner,
ChannelContext {
visibility: ChannelVisibility::Public,
platform: "slack".to_string(),
channel_name: Some("#dev".to_string()),
channel_id: Some("slack:C_ABC".to_string()),
sender_name: None,
sender_id: None,
channel_member_names: vec![],
user_id_map: std::collections::HashMap::new(),
trusted: false,
},
None,
)
.await
.unwrap();
let call_log = harness.provider.call_log.lock().await;
let content_owned: String = call_log[0]
.messages
.iter()
.filter(|m| m["role"] == "system")
.filter_map(|m| m["content"].as_str())
.collect::<Vec<_>>()
.join("\n");
let content = content_owned.as_str();
assert!(
!content.contains("NextJS"),
"Facts should NOT be bulk-injected into system prompt"
);
assert!(
content.contains("Your Memory"),
"System prompt should contain memory capabilities summary"
);
}
#[tokio::test]
async fn test_cross_channel_fact_blocked() {
let harness = setup_test_agent(MockProvider::new()).await.unwrap();
harness
.state
.upsert_fact(
"project",
"secret_plan",
"Launch product in March",
"user",
Some("slack:C_ALPHA"),
crate::types::FactPrivacy::Channel,
)
.await
.unwrap();
harness
.agent
.handle_message(
"cross_ch_session",
"what is our launch plan?",
None,
UserRole::Owner,
ChannelContext {
visibility: ChannelVisibility::Public,
platform: "slack".to_string(),
channel_name: Some("#general".to_string()),
channel_id: Some("slack:C_BETA".to_string()),
sender_name: None,
sender_id: None,
channel_member_names: vec![],
user_id_map: std::collections::HashMap::new(),
trusted: false,
},
None,
)
.await
.unwrap();
let call_log = harness.provider.call_log.lock().await;
let content_owned: String = call_log[0]
.messages
.iter()
.filter(|m| m["role"] == "system")
.filter_map(|m| m["content"].as_str())
.collect::<Vec<_>>()
.join("\n");
let content = content_owned.as_str();
let facts_section_end = content
.find("Cross-Channel Context")
.unwrap_or(content.len());
let facts_section = &content[..facts_section_end];
assert!(
!facts_section.contains("Launch product in March"),
"Channel-scoped fact from another channel should NOT appear in main facts"
);
}
#[tokio::test]
async fn test_dm_recalls_all_facts() {
let harness = setup_test_agent(MockProvider::new()).await.unwrap();
harness
.agent
.handle_message(
"dm_all_facts",
"what do you know about my guitar hobby",
None,
UserRole::Owner,
ChannelContext::private("telegram"),
None,
)
.await
.unwrap();
let call_log = harness.provider.call_log.lock().await;
let content_owned: String = call_log[0]
.messages
.iter()
.filter(|m| m["role"] == "system")
.filter_map(|m| m["content"].as_str())
.collect::<Vec<_>>()
.join("\n");
let content = content_owned.as_str();
assert!(
content.contains("manage_memories"),
"DM prompt should reference manage_memories for on-demand fact retrieval"
);
}
#[tokio::test]
async fn test_private_facts_never_in_channels() {
let harness = setup_test_agent(MockProvider::new()).await.unwrap();
harness
.state
.upsert_fact(
"preference",
"travel",
"Prefers window seats on flights",
"user",
None,
crate::types::FactPrivacy::Private,
)
.await
.unwrap();
harness
.agent
.handle_message(
"priv_fact_session",
"what health info do you have about me?",
None,
UserRole::Owner,
ChannelContext {
visibility: ChannelVisibility::Public,
platform: "slack".to_string(),
channel_name: Some("#general".to_string()),
channel_id: Some("slack:C_GEN".to_string()),
sender_name: None,
sender_id: None,
channel_member_names: vec![],
user_id_map: std::collections::HashMap::new(),
trusted: false,
},
None,
)
.await
.unwrap();
let call_log = harness.provider.call_log.lock().await;
let content_owned: String = call_log[0]
.messages
.iter()
.filter(|m| m["role"] == "system")
.filter_map(|m| m["content"].as_str())
.collect::<Vec<_>>()
.join("\n");
let content = content_owned.as_str();
assert!(
!content.contains("window seats") && !content.contains("Prefers window"),
"Private facts must NEVER appear in public channel prompts"
);
}
#[tokio::test]
async fn test_cross_channel_hints() {
let harness = setup_test_agent(MockProvider::new()).await.unwrap();
harness
.state
.upsert_fact(
"project",
"framework",
"Uses React for frontend",
"user",
Some("slack:C_DEV"),
crate::types::FactPrivacy::Channel,
)
.await
.unwrap();
harness
.agent
.handle_message(
"hints_session",
"what frontend framework should we use?",
None,
UserRole::Owner,
ChannelContext {
visibility: ChannelVisibility::Public,
platform: "slack".to_string(),
channel_name: Some("#general".to_string()),
channel_id: Some("slack:C_GEN".to_string()),
sender_name: None,
sender_id: None,
channel_member_names: vec![],
user_id_map: std::collections::HashMap::new(),
trusted: false,
},
None,
)
.await
.unwrap();
let call_log = harness.provider.call_log.lock().await;
let content_owned: String = call_log[0]
.messages
.iter()
.filter(|m| m["role"] == "system")
.filter_map(|m| m["content"].as_str())
.collect::<Vec<_>>()
.join("\n");
let content = content_owned.as_str();
if content.contains("React") {
assert!(
content.contains("Cross-Channel Context"),
"If React appears, it should be in cross-channel hints section, not main facts"
);
}
}
#[tokio::test]
async fn test_legacy_facts_backward_compat() {
let harness = setup_test_agent(MockProvider::new()).await.unwrap();
harness
.state
.upsert_fact(
"preference",
"editor",
"Uses Neovim",
"agent",
None,
crate::types::FactPrivacy::Global,
)
.await
.unwrap();
harness
.agent
.handle_message(
"legacy_session",
"what editor do I use?",
None,
UserRole::Owner,
ChannelContext {
visibility: ChannelVisibility::Public,
platform: "slack".to_string(),
channel_name: Some("#dev".to_string()),
channel_id: Some("slack:C_DEV".to_string()),
sender_name: None,
sender_id: None,
channel_member_names: vec![],
user_id_map: std::collections::HashMap::new(),
trusted: false,
},
None,
)
.await
.unwrap();
let call_log = harness.provider.call_log.lock().await;
let content_owned: String = call_log[0]
.messages
.iter()
.filter(|m| m["role"] == "system")
.filter_map(|m| m["content"].as_str())
.collect::<Vec<_>>()
.join("\n");
let content = content_owned.as_str();
assert!(
!content.contains("Neovim"),
"Facts should NOT be bulk-injected into system prompt"
);
assert!(
content.contains("Your Memory"),
"System prompt should contain memory capabilities summary"
);
}
#[tokio::test]
async fn test_privacy_upgrade() {
let harness = setup_test_agent(MockProvider::new()).await.unwrap();
harness
.state
.upsert_fact(
"project",
"deadline",
"March 15th launch",
"user",
Some("slack:C_PROJ"),
crate::types::FactPrivacy::Channel,
)
.await
.unwrap();
let facts_before = harness
.state
.get_relevant_facts_for_channel(
"launch deadline",
10,
Some("slack:C_OTHER"),
ChannelVisibility::Public,
)
.await
.unwrap();
let _has_deadline_before = facts_before.iter().any(|f| f.value.contains("March 15th"));
let all_facts = harness.state.get_all_facts_with_provenance().await.unwrap();
let deadline_fact = all_facts.iter().find(|f| f.key == "deadline").unwrap();
harness
.state
.update_fact_privacy(deadline_fact.id, crate::types::FactPrivacy::Global)
.await
.unwrap();
let facts_after = harness
.state
.get_relevant_facts_for_channel(
"launch deadline",
10,
Some("slack:C_OTHER"),
ChannelVisibility::Public,
)
.await
.unwrap();
let _has_deadline_after = facts_after.iter().any(|f| f.value.contains("March 15th"));
let updated_facts = harness.state.get_all_facts_with_provenance().await.unwrap();
let updated = updated_facts.iter().find(|f| f.key == "deadline").unwrap();
assert_eq!(
updated.privacy,
crate::types::FactPrivacy::Global,
"Fact privacy should be upgraded to Global"
);
}
#[tokio::test]
async fn test_memory_management_list() {
let harness = setup_test_agent(MockProvider::new()).await.unwrap();
harness
.state
.upsert_fact(
"project",
"lang",
"Rust",
"user",
Some("slack:C_DEV"),
crate::types::FactPrivacy::Channel,
)
.await
.unwrap();
harness
.state
.upsert_fact(
"personal",
"name",
"Alice",
"user",
None,
crate::types::FactPrivacy::Global,
)
.await
.unwrap();
let all_facts = harness.state.get_all_facts_with_provenance().await.unwrap();
assert!(all_facts.len() >= 2, "Should have at least 2 facts");
let lang_fact = all_facts.iter().find(|f| f.key == "lang").unwrap();
assert_eq!(lang_fact.channel_id.as_deref(), Some("slack:C_DEV"));
assert_eq!(lang_fact.privacy, crate::types::FactPrivacy::Channel);
let name_fact = all_facts.iter().find(|f| f.key == "name").unwrap();
assert_eq!(name_fact.channel_id, None);
assert_eq!(name_fact.privacy, crate::types::FactPrivacy::Global);
}