from __future__ import annotations from datetime import datetime, timezone import pytest from app.agents.chat.agent_turn import AgentChatTurn from app.features.conversation.chat_turn import ( ChatTurnContext, ChatTurnInput, ChatTurnService, ) class _FakeOrchestrator: def __init__(self) -> None: self.calls: list[dict] = [] async def process_user_message(self, **kwargs): self.calls.append(kwargs) return AgentChatTurn( messages=["第一泡", "第二泡"], skip_tts=False, memory_retrieval_trace={"chunks": 1}, interview_state_meta={"recent_questions": ["你当时在哪里?"]}, ) @pytest.mark.asyncio async def test_chat_turn_service_exposes_one_turn_contract() -> None: orchestrator = _FakeOrchestrator() service = ChatTurnService(orchestrator=orchestrator) ts = datetime(2026, 4, 29, tzinfo=timezone.utc) result = await service.process_turn( ChatTurnInput( conversation_id="conv-1", user_message="我小时候住在河边。", is_from_voice=True, voice_session_id="voice-1", user_message_timestamp=ts, audio_duration_seconds=12, force_skip_tts=True, ), ChatTurnContext( db=object(), user=object(), conversation=object(), apply_extracted_profile_fn=lambda *args, **kwargs: None, get_missing_profile_fields_fn=lambda user: [], get_filled_profile_fields_fn=lambda user: {}, ), ) assert result.messages == ["第一泡", "第二泡"] assert result.skip_tts is True assert result.memory_retrieval_trace == {"chunks": 1} assert result.interview_state_meta == { "recent_questions": ["你当时在哪里?"] } assert result.decision.force_skip_tts is True assert len(orchestrator.calls) == 1 call = orchestrator.calls[0] assert call["conversation_id"] == "conv-1" assert call["user_message"] == "我小时候住在河边。" assert call["is_from_voice"] is True assert call["voice_session_id"] == "voice-1" assert call["user_message_timestamp"] is ts assert call["audio_duration_seconds"] == 12