mirror of
https://github.com/whekin/household-bot.git
synced 2026-03-31 17:14:03 +00:00
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.
137 lines
4.0 KiB
TypeScript
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')
|
|
})
|
|
})
|