fix(chatbot): closed session should not block bot re-activation

When a chatbot session exists with status='closed', the emit() method
returned early, preventing the bot from re-activating on new messages.

Root cause: the guard 'if (session.status === closed) return' was meant
to skip sessions not awaiting user input, but it also prevented new
conversations from starting after a bot flow completed.

Fix: nullify the session instead of returning, so processBot enters the
'!session' branch and creates a fresh session.

Also adds null guards:
- getConversationMessage: return empty string instead of undefined
- findBotByTrigger: handle null/undefined content gracefully
This commit is contained in:
Milton Sosa
2026-02-16 04:30:13 -03:00
parent cd800f2976
commit 42b46e0813
3 changed files with 12 additions and 4 deletions
@@ -797,7 +797,7 @@ export abstract class BaseChatbotController<BotType = any, BotData extends BaseC
if (this.checkIgnoreJids(settings?.ignoreJids, remoteJid)) return; if (this.checkIgnoreJids(settings?.ignoreJids, remoteJid)) return;
const session = await this.getSession(remoteJid, instance); let session = await this.getSession(remoteJid, instance);
const content = getConversationMessage(msg); const content = getConversationMessage(msg);
@@ -896,9 +896,9 @@ export abstract class BaseChatbotController<BotType = any, BotData extends BaseC
return; return;
} }
// Skip if session exists but not awaiting user input // If session is closed, nullify it so processBot creates a new conversation
if (session && session.status === 'closed') { if (session && session.status === 'closed') {
return; session = null;
} }
// Merged settings // Merged settings
+8
View File
@@ -1,6 +1,8 @@
import { advancedOperatorsSearch } from './advancedOperatorsSearch'; import { advancedOperatorsSearch } from './advancedOperatorsSearch';
export const findBotByTrigger = async (botRepository: any, content: string, instanceId: string) => { export const findBotByTrigger = async (botRepository: any, content: string, instanceId: string) => {
const normalizedContent = content?.trim() || '';
// Check for triggerType 'all' or 'none' (both should match any message) // Check for triggerType 'all' or 'none' (both should match any message)
const findTriggerAllOrNone = await botRepository.findFirst({ const findTriggerAllOrNone = await botRepository.findFirst({
where: { where: {
@@ -16,6 +18,12 @@ export const findBotByTrigger = async (botRepository: any, content: string, inst
return findTriggerAllOrNone; return findTriggerAllOrNone;
} }
// If content is empty (null, undefined, whitespace-only, or media-only messages),
// only 'all'/'none' triggers apply — skip keyword/regex matching
if (!normalizedContent) {
return null;
}
const findTriggerAdvanced = await botRepository.findMany({ const findTriggerAdvanced = await botRepository.findMany({
where: { where: {
enabled: true, enabled: true,
+1 -1
View File
@@ -76,5 +76,5 @@ export const getConversationMessage = (msg: any) => {
const messageContent = getMessageContent(types); const messageContent = getMessageContent(types);
return messageContent; return messageContent ?? '';
}; };