"""Persona-specific channel and initiation contracts.""" from __future__ import annotations import json import pytest from app.services.persona_generator import PersonaGenerator from app.services.store import ensure_persona_shape, validate_persona_traits from app.api.chat_routes import _scenario_config class StubPersonaLLM: def __init__(self, personas): self.personas = personas def complete_json(self, system_prompt, user_prompt, **kwargs): return {"personas": self.personas} def _persona(channel="line", initiation_mode="customer", **extra): value = { "name": "Customer", "tier": "B", "channel": channel, "initiation_mode": initiation_mode, } value.update(extra) return value def _fifteen(**kwargs): return [_persona(**kwargs) for _ in range(15)] def test_persona_owns_initiation_even_when_scenario_changes(): customer = ensure_persona_shape(_persona(initiation_mode="customer")) seller = ensure_persona_shape(_persona(initiation_mode="seller")) _, customer_mode = _scenario_config("f2f_call", customer, "th") _, seller_mode = _scenario_config("social", seller, "th") assert customer_mode == "customer" assert seller_mode == "seller" def test_channel_and_initiation_are_retained_in_normalized_persona(): persona = ensure_persona_shape(_persona(channel="facebook", initiation_mode="seller")) assert persona["channel"] == "facebook" assert persona["initiation_mode"] == "seller" validate_persona_traits(persona) def test_shape_preserves_explicit_invalid_initiation_for_rejection(): persona = ensure_persona_shape(_persona(initiation_mode="f2f_call")) assert persona["initiation_mode"] == "f2f_call" with pytest.raises(ValueError, match="initiation_mode"): validate_persona_traits(persona) def test_invalid_channel_is_rejected_not_mapped_to_social(): generator = PersonaGenerator(StubPersonaLLM(_fifteen(channel="social"))) with pytest.raises(ValueError, match="channel"): generator.generate(sales_kit={}, language="th", channel="facebook") def test_invalid_initiation_is_rejected_not_mapped_to_customer(): generator = PersonaGenerator(StubPersonaLLM(_fifteen(initiation_mode="f2f_call"))) with pytest.raises(ValueError, match="initiation_mode"): generator.generate(sales_kit={}, language="th", channel="facebook") def test_generator_rejects_invalid_requested_channel(): generator = PersonaGenerator(StubPersonaLLM(_fifteen())) with pytest.raises(ValueError, match="channel"): generator.generate(sales_kit={}, language="th", channel="social")