Files
household-bot/apps/bot/src/topic-message-router.test.ts
whekin f38ee499ae feat(bot): unified topic processor replacing router+interpreter stack
Replace 3-layer architecture (gpt-5-nano router + gpt-4o-mini interpreter) with
single unified topic processor (gpt-4o-mini) for simplified message handling.

New components:
- HouseholdContextCache: TTL-based caching (5 min) for household config data
- TopicProcessor: Unified classification + parsing with structured JSON output

Key changes:
- Renamed ASSISTANT_ROUTER_MODEL → TOPIC_PROCESSOR_MODEL
- Added TOPIC_PROCESSOR_TIMEOUT_MS (default 10s)
- Refactored save() → saveWithInterpretation() for pre-parsed interpretations
- Removed deprecated createOpenAiTopicMessageRouter and ~300 lines legacy code
- Fixed typing indicator to only start when needed (purchase routes)
- Fixed amount formatting: convert minor units to major for rawText

Routes: silent, chat_reply, purchase, purchase_clarification, payment,
payment_clarification, topic_helper, dismiss_workflow

All 212 bot tests pass. Typecheck, lint, format, build clean.
2026-03-14 13:33:57 +04:00

137 lines
4.0 KiB
TypeScript

import { describe, expect, test } from 'bun:test'
import { fallbackTopicMessageRoute } from './topic-message-router'
describe('fallbackTopicMessageRoute', () => {
test('returns silent for empty messages', () => {
const route = fallbackTopicMessageRoute({
locale: 'en',
topicRole: 'purchase',
messageText: '',
isExplicitMention: false,
isReplyToBot: false,
activeWorkflow: null
})
expect(route.route).toBe('silent')
expect(route.reason).toBe('empty')
})
test('returns purchase_followup for active purchase clarification workflow', () => {
const route = fallbackTopicMessageRoute({
locale: 'en',
topicRole: 'purchase',
messageText: 'some message',
isExplicitMention: false,
isReplyToBot: false,
activeWorkflow: 'purchase_clarification'
})
expect(route.route).toBe('purchase_followup')
expect(route.helperKind).toBe('purchase')
})
test('returns payment_followup for active payment clarification workflow', () => {
const route = fallbackTopicMessageRoute({
locale: 'en',
topicRole: 'payments',
messageText: 'some message',
isExplicitMention: false,
isReplyToBot: false,
activeWorkflow: 'payment_clarification'
})
expect(route.route).toBe('payment_followup')
expect(route.helperKind).toBe('payment')
})
test('returns payment_followup for active payment confirmation workflow', () => {
const route = fallbackTopicMessageRoute({
locale: 'en',
topicRole: 'payments',
messageText: 'some message',
isExplicitMention: false,
isReplyToBot: false,
activeWorkflow: 'payment_confirmation'
})
expect(route.route).toBe('payment_followup')
expect(route.helperKind).toBe('payment')
})
test('returns topic_helper for strong reference', () => {
const route = fallbackTopicMessageRoute({
locale: 'en',
topicRole: 'generic',
messageText: 'some message',
isExplicitMention: false,
isReplyToBot: false,
activeWorkflow: null,
engagementAssessment: {
engaged: true,
reason: 'strong_reference',
strongReference: true,
weakSessionActive: false,
hasOpenBotQuestion: false
}
})
expect(route.route).toBe('topic_helper')
expect(route.helperKind).toBe('assistant')
})
test('returns topic_helper for weak session', () => {
const route = fallbackTopicMessageRoute({
locale: 'en',
topicRole: 'generic',
messageText: 'some message',
isExplicitMention: false,
isReplyToBot: false,
activeWorkflow: null,
engagementAssessment: {
engaged: true,
reason: 'weak_session',
strongReference: false,
weakSessionActive: true,
hasOpenBotQuestion: false
}
})
expect(route.route).toBe('topic_helper')
expect(route.helperKind).toBe('assistant')
})
test('returns topic_helper for explicit mention', () => {
const route = fallbackTopicMessageRoute({
locale: 'en',
topicRole: 'generic',
messageText: 'some message',
isExplicitMention: true,
isReplyToBot: false,
activeWorkflow: null
})
expect(route.route).toBe('topic_helper')
expect(route.helperKind).toBe('assistant')
})
test('returns topic_helper for reply to bot', () => {
const route = fallbackTopicMessageRoute({
locale: 'en',
topicRole: 'generic',
messageText: 'some message',
isExplicitMention: false,
isReplyToBot: true,
activeWorkflow: null
})
expect(route.route).toBe('topic_helper')
expect(route.helperKind).toBe('assistant')
})
test('returns silent by default', () => {
const route = fallbackTopicMessageRoute({
locale: 'en',
topicRole: 'generic',
messageText: 'some message',
isExplicitMention: false,
isReplyToBot: false,
activeWorkflow: null
})
expect(route.route).toBe('silent')
expect(route.reason).toBe('quiet_default')
})
})