"""Addressee classifier service tests (T74.1). Covers :func:`chat.services.addressee.detect_addressee`: - Classifier picks the guest -> ``addressee_id == guest_id``. - Classifier picks the host -> ``addressee_id == host_id``. - Classifier flakes (3 bad-JSON responses, exhausting the built-in retry budget in :func:`chat.llm.classify.classify`) -> fallback to the host with ``reason="fallback"``. """ from __future__ import annotations import json import pytest from chat.llm.mock import MockLLMClient from chat.services.addressee import AddresseeDecision, detect_addressee @pytest.mark.asyncio async def test_classifier_picks_guest(): """Classifier returns the guest id verbatim — caller propagates it.""" canned = [ json.dumps( { "addressee_id": "bot_b", "confidence": "high", "reason": "user named BotB", } ) ] client = MockLLMClient(canned=canned) result = await detect_addressee( client, classifier_model="test-model", user_prose="BotB, what do you think?", host_id="bot_a", host_name="BotA", guest_id="bot_b", guest_name="BotB", ) assert isinstance(result, AddresseeDecision) assert result.addressee_id == "bot_b" assert result.confidence == "high" @pytest.mark.asyncio async def test_classifier_picks_host(): """Classifier returns the host id — caller propagates it.""" canned = [ json.dumps( { "addressee_id": "bot_a", "confidence": "medium", "reason": "narration aimed at host", } ) ] client = MockLLMClient(canned=canned) result = await detect_addressee( client, classifier_model="test-model", user_prose="I lean back and stretch.", host_id="bot_a", host_name="BotA", guest_id="bot_b", guest_name="BotB", ) assert result.addressee_id == "bot_a" assert result.confidence == "medium" @pytest.mark.asyncio async def test_classifier_failure_falls_back_to_host(): """Three bad-JSON responses exhaust the retry budget and the classifier-failure fallback returns ``host_id`` with ``reason="fallback"``.""" canned = ["not json", "still not json", "garbage"] client = MockLLMClient(canned=canned) result = await detect_addressee( client, classifier_model="test-model", user_prose="anything", host_id="bot_a", host_name="BotA", guest_id="bot_b", guest_name="BotB", ) assert result.addressee_id == "bot_a" assert result.reason == "fallback" assert result.confidence == "low"