huskies: merge 629_refactor_migrate_commanddispatch_and_commandcontext_to_services_bundle

This commit is contained in:
dave
2026-04-25 20:37:10 +00:00
parent 2a3f88fdcf
commit 14b158d0b2
27 changed files with 407 additions and 544 deletions
+40 -44
View File
@@ -16,7 +16,7 @@ pub(super) fn handle_ambient(ctx: &CommandContext) -> Option<String> {
_ => return Some("Usage: `ambient on` or `ambient off`".to_string()),
};
let room_ids: Vec<String> = {
let mut ambient = ctx.ambient_rooms.lock().unwrap();
let mut ambient = ctx.services.ambient_rooms.lock().unwrap();
if enable {
ambient.insert(ctx.room_id.to_string());
} else {
@@ -24,7 +24,7 @@ pub(super) fn handle_ambient(ctx: &CommandContext) -> Option<String> {
}
ambient.iter().cloned().collect()
};
save_ambient_rooms(ctx.project_root, &room_ids);
save_ambient_rooms(ctx.effective_root(), &room_ids);
let msg = if enable {
"Ambient mode on. I'll respond to all messages in this room."
} else {
@@ -35,35 +35,23 @@ pub(super) fn handle_ambient(ctx: &CommandContext) -> Option<String> {
#[cfg(test)]
mod tests {
use crate::agents::AgentPool;
use std::collections::HashSet;
use std::sync::{Arc, Mutex};
use super::super::{CommandDispatch, try_handle_command};
fn test_ambient_rooms() -> Arc<Mutex<HashSet<String>>> {
Arc::new(Mutex::new(HashSet::new()))
}
fn test_agents() -> Arc<AgentPool> {
Arc::new(AgentPool::new_test(3000))
}
// Bug 352: ambient commands were being forwarded to LLM after refactors
// 328/330 because handle_ambient required is_addressed=true, but
// mentions_bot() only matches @-prefixed mentions, not bare bot names.
// "timmy ambient off" sets is_addressed=false even though it names the bot.
#[test]
fn ambient_on_works_when_unaddressed() {
let ambient_rooms = test_ambient_rooms();
let services = crate::services::Services::new_test(
std::path::PathBuf::from("/tmp"),
"Timmy".to_string(),
);
let room_id = "!myroom:example.com".to_string();
let agents = test_agents();
let dispatch = CommandDispatch {
bot_name: "Timmy",
services: &services,
project_root: &services.project_root,
bot_user_id: "@timmy:homeserver.local",
project_root: std::path::Path::new("/tmp"),
agents: &agents,
ambient_rooms: &ambient_rooms,
room_id: &room_id,
};
// "timmy ambient on" — bot name mentioned but not @-prefixed, so
@@ -74,23 +62,27 @@ mod tests {
"ambient on should fire even when is_addressed=false"
);
assert!(
ambient_rooms.lock().unwrap().contains(&room_id),
services.ambient_rooms.lock().unwrap().contains(&room_id),
"room should be in ambient_rooms after ambient on"
);
}
#[test]
fn ambient_off_works_bare_in_ambient_room() {
let ambient_rooms = test_ambient_rooms();
let services = crate::services::Services::new_test(
std::path::PathBuf::from("/tmp"),
"Timmy".to_string(),
);
let room_id = "!myroom:example.com".to_string();
ambient_rooms.lock().unwrap().insert(room_id.clone());
let agents = test_agents();
services
.ambient_rooms
.lock()
.unwrap()
.insert(room_id.clone());
let dispatch = CommandDispatch {
bot_name: "Timmy",
services: &services,
project_root: &services.project_root,
bot_user_id: "@timmy:homeserver.local",
project_root: std::path::Path::new("/tmp"),
agents: &agents,
ambient_rooms: &ambient_rooms,
room_id: &room_id,
};
// Bare "ambient off" in an ambient room (is_addressed=false).
@@ -105,22 +97,22 @@ mod tests {
"response should confirm ambient off: {output}"
);
assert!(
!ambient_rooms.lock().unwrap().contains(&room_id),
!services.ambient_rooms.lock().unwrap().contains(&room_id),
"room should be removed from ambient_rooms after ambient off"
);
}
#[test]
fn ambient_on_enables_ambient_mode() {
let ambient_rooms = test_ambient_rooms();
let agents = test_agents();
let services = crate::services::Services::new_test(
std::path::PathBuf::from("/tmp"),
"Timmy".to_string(),
);
let room_id = "!myroom:example.com".to_string();
let dispatch = CommandDispatch {
bot_name: "Timmy",
services: &services,
project_root: &services.project_root,
bot_user_id: "@timmy:homeserver.local",
project_root: std::path::Path::new("/tmp"),
agents: &agents,
ambient_rooms: &ambient_rooms,
room_id: &room_id,
};
let result = try_handle_command(&dispatch, "@timmy ambient on");
@@ -131,25 +123,29 @@ mod tests {
"response should confirm ambient on: {output}"
);
assert!(
ambient_rooms.lock().unwrap().contains(&room_id),
services.ambient_rooms.lock().unwrap().contains(&room_id),
"room should be in ambient_rooms after ambient on"
);
}
#[test]
fn ambient_off_disables_ambient_mode() {
let ambient_rooms = test_ambient_rooms();
let agents = test_agents();
let services = crate::services::Services::new_test(
std::path::PathBuf::from("/tmp"),
"Timmy".to_string(),
);
let room_id = "!myroom:example.com".to_string();
// Pre-insert the room
ambient_rooms.lock().unwrap().insert(room_id.clone());
services
.ambient_rooms
.lock()
.unwrap()
.insert(room_id.clone());
let dispatch = CommandDispatch {
bot_name: "Timmy",
services: &services,
project_root: &services.project_root,
bot_user_id: "@timmy:homeserver.local",
project_root: std::path::Path::new("/tmp"),
agents: &agents,
ambient_rooms: &ambient_rooms,
room_id: &room_id,
};
let result = try_handle_command(&dispatch, "@timmy ambient off");
@@ -160,7 +156,7 @@ mod tests {
"response should confirm ambient off: {output}"
);
assert!(
!ambient_rooms.lock().unwrap().contains(&room_id),
!services.ambient_rooms.lock().unwrap().contains(&room_id),
"room should be removed from ambient_rooms after ambient off"
);
}