story-kit: merge 328_refactor_split_commands_rs_into_individual_command_handler_modules

This commit is contained in:
Dave
2026-03-20 07:26:44 +00:00
parent 67e6a4afe6
commit eea797975b
9 changed files with 2045 additions and 1947 deletions
+142
View File
@@ -0,0 +1,142 @@
//! Handler for the `ambient` command.
use super::CommandContext;
use crate::matrix::config::save_ambient_rooms;
/// Toggle ambient mode for this room.
///
/// Only acts when the message directly addressed the bot (`is_addressed=true`)
/// to prevent accidental toggling via ambient-mode traffic.
pub(super) fn handle_ambient(ctx: &CommandContext) -> Option<String> {
if !ctx.is_addressed {
return None;
}
let enable = match ctx.args {
"on" => true,
"off" => false,
_ => return Some("Usage: `ambient on` or `ambient off`".to_string()),
};
let room_ids: Vec<String> = {
let mut ambient = ctx.ambient_rooms.lock().unwrap();
if enable {
ambient.insert(ctx.room_id.to_string());
} else {
ambient.remove(ctx.room_id);
}
ambient.iter().cloned().collect()
};
save_ambient_rooms(ctx.project_root, &room_ids);
let msg = if enable {
"Ambient mode on. I'll respond to all messages in this room."
} else {
"Ambient mode off. I'll only respond when mentioned."
};
Some(msg.to_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))
}
#[test]
fn ambient_on_requires_addressed() {
let ambient_rooms = test_ambient_rooms();
let room_id = "!myroom:example.com".to_string();
let agents = test_agents();
let dispatch = CommandDispatch {
bot_name: "Timmy",
bot_user_id: "@timmy:homeserver.local",
project_root: std::path::Path::new("/tmp"),
agents: &agents,
ambient_rooms: &ambient_rooms,
room_id: &room_id,
is_addressed: false, // not addressed
};
let result = try_handle_command(&dispatch, "@timmy ambient on");
// Should fall through to LLM when not addressed
assert!(result.is_none(), "ambient should not fire in non-addressed mode");
assert!(
!ambient_rooms.lock().unwrap().contains(&room_id),
"ambient_rooms should not be modified when not addressed"
);
}
#[test]
fn ambient_on_enables_ambient_mode() {
let ambient_rooms = test_ambient_rooms();
let agents = test_agents();
let room_id = "!myroom:example.com".to_string();
let dispatch = CommandDispatch {
bot_name: "Timmy",
bot_user_id: "@timmy:homeserver.local",
project_root: std::path::Path::new("/tmp"),
agents: &agents,
ambient_rooms: &ambient_rooms,
room_id: &room_id,
is_addressed: true,
};
let result = try_handle_command(&dispatch, "@timmy ambient on");
assert!(result.is_some(), "ambient on should produce a response");
let output = result.unwrap();
assert!(
output.contains("Ambient mode on"),
"response should confirm ambient on: {output}"
);
assert!(
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 room_id = "!myroom:example.com".to_string();
// Pre-insert the room
ambient_rooms.lock().unwrap().insert(room_id.clone());
let dispatch = CommandDispatch {
bot_name: "Timmy",
bot_user_id: "@timmy:homeserver.local",
project_root: std::path::Path::new("/tmp"),
agents: &agents,
ambient_rooms: &ambient_rooms,
room_id: &room_id,
is_addressed: true,
};
let result = try_handle_command(&dispatch, "@timmy ambient off");
assert!(result.is_some(), "ambient off should produce a response");
let output = result.unwrap();
assert!(
output.contains("Ambient mode off"),
"response should confirm ambient off: {output}"
);
assert!(
!ambient_rooms.lock().unwrap().contains(&room_id),
"room should be removed from ambient_rooms after ambient off"
);
}
#[test]
fn ambient_invalid_args_returns_usage() {
let result = super::super::tests::try_cmd_addressed("Timmy", "@timmy:homeserver.local", "@timmy ambient");
let output = result.unwrap();
assert!(
output.contains("Usage"),
"invalid ambient args should show usage: {output}"
);
}
}