feat: NLU fallback — route unrecognized text to AI in hybrid+NLU mode

NormalBot.process() gains suppressFallback param. When true, steps 7-8
(greeting menu fallback, static fallback text) return null instead of
responding, letting BotRouter hand off to NLU/AI.

BotRouter.runHybridBot() passes suppressFallback=$nluEnabled so that:
- NLU on: unrecognized text → NLU → route to flow or AI chat
- NLU off: existing fallback behavior unchanged
- Commands, active flows, first-session greeting: always unaffected

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-07-05 09:09:49 -05:00
co-authored by Claude Sonnet 4.6
parent 54d778783e
commit 497743ceb1
2 changed files with 264 additions and 45 deletions
+5 -3
View File
@@ -87,12 +87,12 @@ class BotRouter
};
}
private static function runNormalBot(array $company, array $context, string $input, string $inputType): ?array
private static function runNormalBot(array $company, array $context, string $input, string $inputType, bool $suppressFallback = false): ?array
{
if ($inputType === 'interactive' || $inputType === 'button') {
return NormalBot::processInteractive($company, $context, $input);
}
return NormalBot::process($company, $context, $input);
return NormalBot::process($company, $context, $input, $suppressFallback);
}
private static function runAiBot(array $company, array $context, string $input): ?array
@@ -140,7 +140,9 @@ class BotRouter
}
// ── Texto / interactivo: NormalBot primero ────────────────────────────
$response = self::runNormalBot($company, $context, $input, $inputType);
// suppressFallback=true cuando NLU activo: si NormalBot no reconoce, retorna null
// y dejamos que NLU decida en vez de mostrar el menú de bienvenida como fallback
$response = self::runNormalBot($company, $context, $input, $inputType, $nluEnabled);
if ($response !== null) {
return $response;
}