from __future__ import annotations from asgiref.sync import async_to_sync from django.test import TestCase from core.commands.base import CommandContext from core.commands.engine import _matches_trigger, process_inbound_message from core.messaging.reply_sync import extract_reply_ref, resolve_reply_target from core.views.compose import _command_options_for_channel from core.models import ( ChatSession, CommandAction, CommandChannelBinding, CommandProfile, CommandVariantPolicy, Message, Person, PersonIdentifier, User, ) class Phase1ReplyResolutionTests(TestCase): def setUp(self): self.user = User.objects.create_user( username="phase1-reply-user", email="phase1-reply@example.com", password="x", ) self.person = Person.objects.create(user=self.user, name="Reply Person") self.identifier = PersonIdentifier.objects.create( user=self.user, person=self.person, service="signal", identifier="+15550000001", ) self.session = ChatSession.objects.create( user=self.user, identifier=self.identifier, ) def test_resolve_reply_target_by_source_message_id(self): anchor = Message.objects.create( user=self.user, session=self.session, sender_uuid="+15550000001", text="anchor", ts=1000, source_service="signal", source_message_id="signal-msg-1", ) resolved = async_to_sync(resolve_reply_target)( self.user, self.session, { "reply_source_service": "signal", "reply_source_message_id": "signal-msg-1", }, ) self.assertEqual(anchor.id, resolved.id if resolved else None) def test_resolve_reply_target_with_bridge_ref_fallback(self): anchor = Message.objects.create( user=self.user, session=self.session, sender_uuid="+15550000001", text="anchor", ts=2000, receipt_payload={ "bridge_refs": { "signal": [ { "xmpp_message_id": "xmpp-bridge-1", "upstream_message_id": "signal-upstream-1", "upstream_author": "+15550000001", "upstream_ts": 2000, "updated_at": 2000, } ] } }, ) resolved = async_to_sync(resolve_reply_target)( self.user, self.session, { "reply_source_service": "signal", "reply_source_message_id": "signal-upstream-1", }, ) self.assertEqual(anchor.id, resolved.id if resolved else None) def test_resolve_reply_target_miss(self): resolved = async_to_sync(resolve_reply_target)( self.user, self.session, { "reply_source_service": "signal", "reply_source_message_id": "does-not-exist", }, ) self.assertIsNone(resolved) def test_extract_reply_ref_xmpp(self): result = extract_reply_ref( "xmpp", { "reply_source_message_id": "xmpp-msg-1", "reply_source_chat_id": "alice@example.test", }, ) self.assertEqual("xmpp-msg-1", result.get("reply_source_message_id")) self.assertEqual("xmpp", result.get("reply_source_service")) def test_extract_reply_ref_signal(self): result = extract_reply_ref( "signal", { "envelope": { "dataMessage": { "quote": {"id": "signal-msg-quoted"}, } } }, ) self.assertEqual("signal-msg-quoted", result.get("reply_source_message_id")) self.assertEqual("signal", result.get("reply_source_service")) def test_extract_reply_ref_signal_target_sent_timestamp_variant(self): result = extract_reply_ref( "signal", { "envelope": { "dataMessage": { "quote": { "targetSentTimestamp": 1772545268786, "authorNumber": "+15550000001", } } } }, ) self.assertEqual( "1772545268786", result.get("reply_source_message_id"), ) self.assertEqual("signal", result.get("reply_source_service")) self.assertEqual("+15550000001", result.get("reply_source_chat_id")) def test_extract_reply_ref_whatsapp(self): result = extract_reply_ref( "whatsapp", { "extendedTextMessage": { "contextInfo": { "stanzaId": "wa-msg-quoted", "participant": "12345@s.whatsapp.net", } } }, ) self.assertEqual("wa-msg-quoted", result.get("reply_source_message_id")) self.assertEqual("whatsapp", result.get("reply_source_service")) def test_extract_reply_ref_whatsapp_stanza_id_variant(self): result = extract_reply_ref( "whatsapp", { "extendedTextMessage": { "contextInfo": { "stanzaID": "wa-msg-quoted-2", } } }, ) self.assertEqual("wa-msg-quoted-2", result.get("reply_source_message_id")) self.assertEqual("whatsapp", result.get("reply_source_service")) class Phase1CommandEngineTests(TestCase): def setUp(self): self.user = User.objects.create_user( username="phase1-command-user", email="phase1-command@example.com", password="x", ) self.person = Person.objects.create(user=self.user, name="Command Person") self.identifier = PersonIdentifier.objects.create( user=self.user, person=self.person, service="signal", identifier="+15550000002", ) self.session = ChatSession.objects.create( user=self.user, identifier=self.identifier, ) self.profile = CommandProfile.objects.create( user=self.user, slug="bp", name="Business Plan", enabled=True, trigger_token="#bp#", reply_required=True, exact_match_only=True, ) CommandChannelBinding.objects.create( profile=self.profile, direction="ingress", service="web", channel_identifier="web-chan-1", enabled=True, ) def test_matches_trigger_exact_only(self): self.assertTrue(_matches_trigger(self.profile, "#bp#")) self.assertFalse(_matches_trigger(self.profile, " #bp# extra ")) def test_process_inbound_message_requires_reply(self): msg = Message.objects.create( user=self.user, session=self.session, sender_uuid="", text="#bp#", ts=3000, source_service="web", source_chat_id="web-chan-1", message_meta={}, ) results = async_to_sync(process_inbound_message)( CommandContext( service="web", channel_identifier="web-chan-1", message_id=str(msg.id), user_id=self.user.id, message_text="#bp#", payload={}, ) ) self.assertEqual(1, len(results)) self.assertEqual("skipped", results[0].status) self.assertEqual("reply_required", results[0].error) def test_process_inbound_message_skips_mirrored_origin(self): msg = Message.objects.create( user=self.user, session=self.session, sender_uuid="", text="#bp#", ts=4000, source_service="web", source_chat_id="web-chan-1", message_meta={"origin_tag": "translation:test"}, ) results = async_to_sync(process_inbound_message)( CommandContext( service="web", channel_identifier="web-chan-1", message_id=str(msg.id), user_id=self.user.id, message_text="#bp#", payload={}, ) ) self.assertEqual([], results) def test_eligible_profile_matches_whatsapp_group_identifier_variants(self): self.profile.channel_bindings.all().delete() CommandChannelBinding.objects.create( profile=self.profile, direction="ingress", service="whatsapp", channel_identifier="120363402761690215@g.us", enabled=True, ) msg = Message.objects.create( user=self.user, session=self.session, sender_uuid="", text="#bp#", ts=5000, source_service="whatsapp", source_chat_id="120363402761690215@g.us", message_meta={}, ) results = async_to_sync(process_inbound_message)( CommandContext( service="whatsapp", channel_identifier="120363402761690215", message_id=str(msg.id), user_id=self.user.id, message_text="#bp#", payload={}, ) ) self.assertEqual(1, len(results)) self.assertEqual("skipped", results[0].status) self.assertEqual("reply_required", results[0].error) def test_compose_command_options_show_bp_subcommands(self): self.profile.channel_bindings.all().delete() CommandChannelBinding.objects.create( profile=self.profile, direction="ingress", service="whatsapp", channel_identifier="120363402761690215@g.us", enabled=True, ) options = _command_options_for_channel( self.user, "whatsapp", "120363402761690215@g.us", ) names = [str(row.get("name") or "").strip().lower() for row in options] self.assertIn("bp", names) self.assertIn("bp set", names) self.assertIn("bp set range", names) self.assertIn("codex", names) self.assertNotIn("announce task ids", names) def test_first_user_codex_command_auto_enables_defaults_for_channel(self): CommandProfile.objects.filter(user=self.user, slug="codex").delete() msg = Message.objects.create( user=self.user, session=self.session, sender_uuid="", custom_author="USER", text="#codex status#", ts=6000, source_service="web", source_chat_id="web-chan-2", message_meta={}, ) results = async_to_sync(process_inbound_message)( CommandContext( service="web", channel_identifier="web-chan-2", message_id=str(msg.id), user_id=self.user.id, message_text="#codex status#", payload={}, ) ) self.assertEqual(1, len(results)) self.assertTrue(results[0].ok) profile = CommandProfile.objects.filter(user=self.user, slug="codex").first() self.assertIsNotNone(profile) self.assertTrue(bool(profile.enabled if profile else False)) ingress_exists = CommandChannelBinding.objects.filter( profile=profile, direction="ingress", enabled=True, service="signal", channel_identifier="+15550000002", ).exists() egress_exists = CommandChannelBinding.objects.filter( profile=profile, direction="egress", enabled=True, service="signal", channel_identifier="+15550000002", ).exists() self.assertTrue(ingress_exists) self.assertTrue(egress_exists) def test_first_user_bp_command_auto_setup_is_idempotent(self): CommandProfile.objects.filter(user=self.user, slug="bp").delete() msg1 = Message.objects.create( user=self.user, session=self.session, sender_uuid="", custom_author="USER", text="#bp#", ts=7000, source_service="web", source_chat_id="web-chan-3", message_meta={}, ) first_results = async_to_sync(process_inbound_message)( CommandContext( service="web", channel_identifier="web-chan-3", message_id=str(msg1.id), user_id=self.user.id, message_text="#bp#", payload={}, ) ) self.assertEqual(1, len(first_results)) self.assertEqual("reply_required", first_results[0].error) profile = CommandProfile.objects.filter(user=self.user, slug="bp").first() self.assertIsNotNone(profile) if profile is None: return self.assertEqual(3, CommandAction.objects.filter(profile=profile).count()) self.assertEqual(3, CommandVariantPolicy.objects.filter(profile=profile).count()) self.assertEqual( 2, CommandChannelBinding.objects.filter( profile=profile, service="signal", channel_identifier="+15550000002", ).count(), ) msg2 = Message.objects.create( user=self.user, session=self.session, sender_uuid="", custom_author="USER", text="#bp#", ts=8000, source_service="web", source_chat_id="web-chan-3", message_meta={}, ) second_results = async_to_sync(process_inbound_message)( CommandContext( service="web", channel_identifier="web-chan-3", message_id=str(msg2.id), user_id=self.user.id, message_text="#bp#", payload={}, ) ) self.assertEqual(1, len(second_results)) self.assertEqual("reply_required", second_results[0].error) self.assertEqual(3, CommandAction.objects.filter(profile=profile).count()) self.assertEqual(3, CommandVariantPolicy.objects.filter(profile=profile).count()) self.assertEqual( 2, CommandChannelBinding.objects.filter( profile=profile, service="signal", channel_identifier="+15550000002", ).count(), )