#[tokio::test]
async fn test_memory_episodes_injected_into_prompt() {
let harness = setup_test_agent(MockProvider::new()).await.unwrap();
harness
.agent
.handle_message(
"ep_session",
"I have a Rust error",
None,
UserRole::Owner,
ChannelContext::private("test"),
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("Past Sessions"),
"System prompt should NOT contain bulk episode data"
);
assert!(
content.contains("Your Memory"),
"System prompt should contain memory capabilities summary"
);
}
#[tokio::test]
async fn test_memory_goals_injected_into_prompt() {
let harness = setup_test_agent(MockProvider::new()).await.unwrap();
let mut goal = Goal::new_finite(
"Migrate the database from PostgreSQL to SQLite",
"goal_session",
);
goal.domain = "personal".to_string();
goal.priority = "high".to_string();
harness.state.create_goal(&goal).await.unwrap();
harness
.agent
.handle_message(
"goal_session",
"what should I work on?",
None,
UserRole::Owner,
ChannelContext::private("test"),
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("PostgreSQL"),
"Goal descriptions should NOT be bulk-injected into prompt"
);
assert!(
content.contains("scheduled_goals"),
"System prompt should reference scheduled_goals tool for on-demand access"
);
}
#[tokio::test]
async fn test_memory_procedures_injected_into_prompt() {
let harness = setup_test_agent(MockProvider::new()).await.unwrap();
harness
.agent
.handle_message(
"proc_session",
"deploy release",
None,
UserRole::Owner,
ChannelContext::private("test"),
None,
)
.await
.unwrap();
let call_log = harness.provider.call_log.lock().await;
assert!(!call_log.is_empty(), "Expected at least 1 LLM call");
let sys = call_log[0]
.messages
.iter()
.find(|m| m.get("role").and_then(|r| r.as_str()) == Some("system"))
.expect("No system message found");
let content = sys["content"].as_str().unwrap();
assert!(
!content.contains("Known Procedures"),
"Procedures should NOT be bulk-injected into prompt"
);
}
#[tokio::test]
async fn test_memory_error_solutions_injected_into_prompt() {
let harness = setup_test_agent(MockProvider::new()).await.unwrap();
harness
.agent
.handle_message(
"err_session",
"connection refused port 5432",
None,
UserRole::Owner,
ChannelContext::private("test"),
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("Error Solutions"),
"Error solutions should NOT be bulk-injected into prompt"
);
}
#[tokio::test]
async fn test_memory_expertise_injected_into_prompt() {
let harness = setup_test_agent(MockProvider::new()).await.unwrap();
harness
.agent
.handle_message(
"exp_session",
"help me with code",
None,
UserRole::Owner,
ChannelContext::private("test"),
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("Expertise Levels"),
"Expertise levels should NOT be bulk-injected into prompt"
);
}
#[tokio::test]
async fn test_memory_behavior_patterns_injected_into_prompt() {
let harness = setup_test_agent(MockProvider::new()).await.unwrap();
harness
.agent
.handle_message(
"pat_session",
"I want to commit",
None,
UserRole::Owner,
ChannelContext::private("test"),
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("Observed Patterns"),
"Behavior patterns should NOT be bulk-injected into prompt"
);
}
#[tokio::test]
async fn test_memory_failure_patterns_injected_into_prompt() {
let harness = setup_test_agent(MockProvider::new()).await.unwrap();
harness
.agent
.handle_message(
"failure_pattern_session",
"help me debug this command issue",
None,
UserRole::Owner,
ChannelContext::private("test"),
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("Failure Patterns To Avoid"),
"Failure patterns should NOT be bulk-injected into prompt"
);
}
#[tokio::test]
async fn test_memory_failure_patterns_injected_into_public_prompt() {
let harness = setup_test_agent(MockProvider::new()).await.unwrap();
harness
.agent
.handle_message(
"public_failure_pattern_session",
"help me debug this search workflow",
None,
UserRole::Owner,
ChannelContext {
visibility: ChannelVisibility::Public,
platform: "test".to_string(),
channel_name: Some("#eng".to_string()),
channel_id: Some("test:eng".to_string()),
sender_name: Some("Alice".to_string()),
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("Failure Patterns To Avoid"),
"Failure patterns should NOT be bulk-injected into public prompt"
);
}
#[tokio::test]
async fn test_memory_user_profile_affects_prompt() {
let harness = setup_test_agent(MockProvider::new()).await.unwrap();
let profile = UserProfile {
id: 1,
verbosity_preference: "brief".to_string(),
explanation_depth: "minimal".to_string(),
tone_preference: "casual".to_string(),
emoji_preference: "none".to_string(),
typical_session_length: Some(10),
active_hours: None,
common_workflows: Some(vec!["code review".to_string()]),
asks_before_acting: true,
prefers_explanations: false,
likes_suggestions: true,
updated_at: Utc::now(),
};
harness.state.update_user_profile(&profile).await.unwrap();
harness
.agent
.handle_message(
"profile_session",
"hello",
None,
UserRole::Owner,
ChannelContext::private("test"),
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("Communication Preferences") && content.contains("brief"),
"System prompt should include user profile preferences. Tail: ...{}",
&content[content.len().saturating_sub(800)..]
);
}
#[tokio::test]
async fn test_full_memory_stack_in_system_prompt() {
let harness = setup_test_agent(MockProvider::new()).await.unwrap();
let profile = UserProfile {
id: 1,
verbosity_preference: "detailed".to_string(),
explanation_depth: "thorough".to_string(),
tone_preference: "casual".to_string(),
emoji_preference: "none".to_string(),
typical_session_length: Some(30),
active_hours: None,
common_workflows: Some(vec!["deployment".to_string()]),
asks_before_acting: false,
prefers_explanations: true,
likes_suggestions: true,
updated_at: Utc::now(),
};
harness.state.update_user_profile(&profile).await.unwrap();
harness
.agent
.handle_message(
"full_memory",
"deploy and release",
None,
UserRole::Owner,
ChannelContext::private("test"),
None,
)
.await
.unwrap();
let call_log = harness.provider.call_log.lock().await;
let content: 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.as_str();
assert!(
content.contains("Communication Preferences"),
"User profile should still be injected"
);
assert!(
content.contains("Your Memory"),
"Memory capabilities summary should be present"
);
assert!(
content.contains("manage_memories"),
"Should reference manage_memories tool"
);
let should_not_contain = vec![
"Known Procedures",
"Error Solutions",
"Expertise Levels",
"Active Goals",
"Known Facts",
"Observed Patterns",
"Failure Patterns",
"Trusted Command Patterns",
"Contextual Suggestions",
"Relevant Past Sessions",
];
for marker in &should_not_contain {
assert!(
!content.contains(marker),
"System prompt should NOT contain '{}' — memory is on-demand now",
marker
);
}
}
#[tokio::test]
async fn test_public_channel_hides_personal_memory() {
let harness = setup_test_agent(MockProvider::new()).await.unwrap();
harness
.state
.upsert_fact(
"personal",
"name",
"Alice",
"user",
None,
crate::types::FactPrivacy::Global,
)
.await
.unwrap();
harness
.state
.upsert_fact(
"preference",
"hobby",
"Enjoys photography",
"user",
None,
crate::types::FactPrivacy::Private,
)
.await
.unwrap();
let mut goal = Goal::new_finite("Learn Japanese", "public_chan");
goal.domain = "personal".to_string();
harness.state.create_goal(&goal).await.unwrap();
let proc = Procedure {
id: 0,
name: "Debug crash".to_string(),
trigger_pattern: "crash debug segfault".to_string(),
steps: vec![
"Check logs".to_string(),
"Run with RUST_BACKTRACE=1".to_string(),
],
success_count: 5,
failure_count: 0,
avg_duration_secs: None,
last_used_at: None,
created_at: Utc::now(),
updated_at: Utc::now(),
};
harness.state.upsert_procedure(&proc).await.unwrap();
harness
.agent
.handle_message(
"public_chan",
"my app crashed",
None,
UserRole::Owner,
ChannelContext {
visibility: ChannelVisibility::Public,
platform: "slack".to_string(),
channel_name: Some("general".to_string()),
channel_id: Some("slack:C_TEST".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("Enjoys photography"),
"Private facts should NOT appear in public channel prompt"
);
assert!(
!content.contains("Learn Japanese"),
"Personal goals should NOT appear in public channel prompt"
);
}
#[tokio::test]
async fn test_tool_schemas_gemini_compatible() {
use serde_json::json;
let harness = setup_test_agent(MockProvider::new()).await.unwrap();
let _response = harness
.agent
.handle_message(
"schema_check",
"hello",
None,
UserRole::Owner,
ChannelContext::private("test"),
None,
)
.await
.unwrap();
let call_log = harness.provider.call_log.lock().await;
assert!(!call_log.is_empty(), "Expected at least 1 LLM call");
let tools = &call_log[0].tools;
assert!(!tools.is_empty(), "Expected tools in the LLM call");
let gemini = crate::providers::GoogleGenAiProvider::new("fake-key");
let converted = gemini.convert_tools_for_test(tools, false);
assert!(converted.is_some(), "convert_tools should return Some");
fn assert_no_schema(value: &serde_json::Value, path: &str) {
match value {
serde_json::Value::Object(map) => {
assert!(
!map.contains_key("$schema"),
"Gemini-incompatible '$schema' found at: {}",
path
);
for (k, v) in map {
assert_no_schema(v, &format!("{}.{}", path, k));
}
}
serde_json::Value::Array(arr) => {
for (i, v) in arr.iter().enumerate() {
assert_no_schema(v, &format!("{}[{}]", path, i));
}
}
_ => {}
}
}
assert_no_schema(&json!(converted.unwrap()), "gemini_tools");
}