storkit: merge 400_bug_whatsapp_and_slack_missing_reset_command_handler

This commit is contained in:
dave
2026-03-26 20:14:56 +00:00
parent b5bf75aa5a
commit cd3ded278d
2 changed files with 162 additions and 0 deletions
+81
View File
@@ -863,6 +863,28 @@ async fn handle_incoming_message(
return; return;
} }
if crate::chat::transport::matrix::reset::extract_reset_command(
message,
&ctx.bot_name,
&ctx.bot_user_id,
)
.is_some()
{
slog!("[slack] Handling reset command from {user} in {channel}");
{
let mut guard = ctx.history.lock().await;
let conv = guard.entry(channel.to_string()).or_insert_with(RoomConversation::default);
conv.session_id = None;
conv.entries.clear();
save_slack_history(&ctx.project_root, &guard);
}
let _ = ctx
.transport
.send_message(channel, "Session cleared.", "")
.await;
return;
}
// No command matched — forward to LLM for conversational response. // No command matched — forward to LLM for conversational response.
slog!("[slack] No command matched, forwarding to LLM for {user} in {channel}"); slog!("[slack] No command matched, forwarding to LLM for {user} in {channel}");
handle_llm_message(ctx, channel, user, message).await; handle_llm_message(ctx, channel, user, message).await;
@@ -1725,4 +1747,63 @@ mod tests {
); );
assert!(result.is_none(), "'status' should not be recognised as rebuild"); assert!(result.is_none(), "'status' should not be recognised as rebuild");
} }
// ── reset command extraction ───────────────────────────────────────
#[test]
fn reset_command_extracted_from_slack_message() {
let result = crate::chat::transport::matrix::reset::extract_reset_command(
"Storkit reset",
"Storkit",
"slack-bot",
);
assert!(result.is_some(), "'Storkit reset' should be recognised");
}
#[test]
fn reset_command_extracted_plain_no_mention() {
let result = crate::chat::transport::matrix::reset::extract_reset_command(
"reset",
"Storkit",
"slack-bot",
);
assert!(result.is_some(), "plain 'reset' should be recognised");
}
#[tokio::test]
async fn reset_command_clears_slack_session() {
use std::sync::Arc;
use tokio::sync::Mutex as TokioMutex;
let channel = "C01ABCDEF";
let history: SlackConversationHistory = Arc::new(TokioMutex::new({
let mut m = HashMap::new();
m.insert(channel.to_string(), RoomConversation {
session_id: Some("old-session".to_string()),
entries: vec![ConversationEntry {
role: ConversationRole::User,
sender: "U01GHIJKL".to_string(),
content: "previous message".to_string(),
}],
});
m
}));
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".storkit");
std::fs::create_dir_all(&sk).unwrap();
{
let mut guard = history.lock().await;
let conv = guard.entry(channel.to_string()).or_insert_with(RoomConversation::default);
conv.session_id = None;
conv.entries.clear();
save_slack_history(tmp.path(), &guard);
}
let guard = history.lock().await;
let conv = guard.get(channel).unwrap();
assert!(conv.session_id.is_none(), "session_id should be cleared");
assert!(conv.entries.is_empty(), "entries should be cleared");
}
} }
+81
View File
@@ -1124,6 +1124,28 @@ async fn handle_incoming_message(ctx: &WhatsAppWebhookContext, sender: &str, mes
return; return;
} }
if crate::chat::transport::matrix::reset::extract_reset_command(
message,
&ctx.bot_name,
&ctx.bot_user_id,
)
.is_some()
{
slog!("[whatsapp] Handling reset command from {sender}");
{
let mut guard = ctx.history.lock().await;
let conv = guard.entry(sender.to_string()).or_insert_with(RoomConversation::default);
conv.session_id = None;
conv.entries.clear();
save_whatsapp_history(&ctx.project_root, &guard);
}
let _ = ctx
.transport
.send_message(sender, "Session cleared.", "")
.await;
return;
}
// No command matched — forward to LLM for conversational response. // No command matched — forward to LLM for conversational response.
slog!("[whatsapp] No command matched, forwarding to LLM for {sender}"); slog!("[whatsapp] No command matched, forwarding to LLM for {sender}");
handle_llm_message(ctx, sender, message).await; handle_llm_message(ctx, sender, message).await;
@@ -2127,4 +2149,63 @@ mod tests {
assert!(loaded.contains_key("222")); assert!(loaded.contains_key("222"));
assert_eq!(loaded["222"].session_id.as_deref(), Some("sess-222")); assert_eq!(loaded["222"].session_id.as_deref(), Some("sess-222"));
} }
// ── reset command extraction ───────────────────────────────────────
#[test]
fn reset_command_extracted_from_plain_message() {
let result = crate::chat::transport::matrix::reset::extract_reset_command(
"reset",
"Timmy",
"@timmy:home.local",
);
assert!(result.is_some(), "plain 'reset' should be recognised");
}
#[test]
fn reset_command_extracted_with_bot_name_prefix() {
let result = crate::chat::transport::matrix::reset::extract_reset_command(
"Timmy reset",
"Timmy",
"@timmy:home.local",
);
assert!(result.is_some(), "'Timmy reset' should be recognised");
}
#[tokio::test]
async fn reset_command_clears_whatsapp_session() {
use std::sync::Arc;
use tokio::sync::Mutex as TokioMutex;
let sender = "+15555550100";
let history: WhatsAppConversationHistory = Arc::new(TokioMutex::new({
let mut m = HashMap::new();
m.insert(sender.to_string(), RoomConversation {
session_id: Some("old-session".to_string()),
entries: vec![ConversationEntry {
role: ConversationRole::User,
sender: sender.to_string(),
content: "previous message".to_string(),
}],
});
m
}));
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".storkit");
std::fs::create_dir_all(&sk).unwrap();
{
let mut guard = history.lock().await;
let conv = guard.entry(sender.to_string()).or_insert_with(RoomConversation::default);
conv.session_id = None;
conv.entries.clear();
save_whatsapp_history(tmp.path(), &guard);
}
let guard = history.lock().await;
let conv = guard.get(sender).unwrap();
assert!(conv.session_id.is_none(), "session_id should be cleared");
assert!(conv.entries.is_empty(), "entries should be cleared");
}
} }