From 060562428eae941f1c64e6d82114136f2191a95a Mon Sep 17 00:00:00 2001
From: = <=>
Date: Tue, 15 Jul 2025 13:32:31 -0700
Subject: [PATCH 1/3] port test case from botframework for turn-context
---
.../tests/test_turn_context.py | 420 ++++++++++++++++++
1 file changed, 420 insertions(+)
create mode 100644 libraries/Builder/microsoft-agents-builder/tests/test_turn_context.py
diff --git a/libraries/Builder/microsoft-agents-builder/tests/test_turn_context.py b/libraries/Builder/microsoft-agents-builder/tests/test_turn_context.py
new file mode 100644
index 00000000..8ae8cac2
--- /dev/null
+++ b/libraries/Builder/microsoft-agents-builder/tests/test_turn_context.py
@@ -0,0 +1,420 @@
+import pytest
+from typing import Callable, List
+
+from microsoft.agents.core.models import (
+ Activity,
+ ActivityTypes,
+ ChannelAccount,
+ ConversationAccount,
+ Entity,
+ Mention,
+ ResourceResponse,
+)
+from microsoft.agents.builder import ChannelAdapter, MessageFactory, TurnContext
+
+activity_data = {
+ "type": "message",
+ "id": "1234",
+ "text":"test",
+ "from_property": ChannelAccount(id="user", name="User Name"),
+ "recipient": ChannelAccount(id="bot", name="Bot Name"),
+ "conversation": ConversationAccount(id="convo", name="Convo Name"),
+ "channel_id":"UnitTest",
+ "locale":"en-uS",
+ "service_url":"https://example.org",
+}
+
+ACTIVITY = Activity(**activity_data)
+
+
+class MockSimpleAdapter(ChannelAdapter):
+ async def send_activities(self, context, activities) -> List[ResourceResponse]:
+ responses = []
+ assert context is not None
+ assert activities is not None
+ assert isinstance(activities, list)
+ assert activities
+ for idx, activity in enumerate(activities): # pylint: disable=unused-variable
+ assert isinstance(activity, Activity)
+ assert activity.type == "message" or activity.type == ActivityTypes.trace
+ responses.append(ResourceResponse(id="5678"))
+ return responses
+
+ async def update_activity(self, context, activity):
+ assert context is not None
+ assert activity is not None
+ assert activity.id is not None
+ return ResourceResponse(id=activity.id)
+
+ async def delete_activity(self, context, reference):
+ assert context is not None
+ assert reference is not None
+ assert reference.activity_id == ACTIVITY.id
+
+
+class TestTurnContext:
+ def test_should_create_context_with_request_and_adapter(self):
+ TurnContext(MockSimpleAdapter(), ACTIVITY)
+
+ def test_should_not_create_context_without_request(self):
+ try:
+ TurnContext(MockSimpleAdapter(), None)
+ except TypeError:
+ pass
+ except Exception as error:
+ raise error
+
+ def test_should_not_create_context_without_adapter(self):
+ try:
+ TurnContext(None, ACTIVITY)
+ except TypeError:
+ pass
+ except Exception as error:
+ raise error
+
+ def test_should_create_context_with_older_context(self):
+ context = TurnContext(MockSimpleAdapter(), ACTIVITY)
+ TurnContext(context)
+
+ def test_copy_to_should_copy_all_references(self):
+ # pylint: disable=protected-access
+ old_adapter = MockSimpleAdapter()
+ old_activity = Activity(id="2", type="message", text="test copy")
+ old_context = TurnContext(old_adapter, old_activity)
+ old_context.responded = True
+
+ async def send_activities_handler(context, activities, next_handler):
+ assert context is not None
+ assert activities is not None
+ assert next_handler is not None
+ await next_handler
+
+ async def delete_activity_handler(context, reference, next_handler):
+ assert context is not None
+ assert reference is not None
+ assert next_handler is not None
+ await next_handler
+
+ async def update_activity_handler(context, activity, next_handler):
+ assert context is not None
+ assert activity is not None
+ assert next_handler is not None
+ await next_handler
+
+ old_context.on_send_activities(send_activities_handler)
+ old_context.on_delete_activity(delete_activity_handler)
+ old_context.on_update_activity(update_activity_handler)
+
+ adapter = MockSimpleAdapter()
+ new_context = TurnContext(adapter, ACTIVITY)
+ assert not new_context._on_send_activities # pylint: disable=protected-access
+ assert not new_context._on_update_activity # pylint: disable=protected-access
+ assert not new_context._on_delete_activity # pylint: disable=protected-access
+
+ old_context.copy_to(new_context)
+
+ assert new_context.adapter == old_adapter
+ assert new_context.activity == old_activity
+ assert new_context.responded is True
+ assert (
+ len(new_context._on_send_activities) == 1
+ ) # pylint: disable=protected-access
+ assert (
+ len(new_context._on_update_activity) == 1
+ ) # pylint: disable=protected-access
+ assert (
+ len(new_context._on_delete_activity) == 1
+ ) # pylint: disable=protected-access
+
+ def test_responded_should_be_automatically_set_to_false(self):
+ context = TurnContext(MockSimpleAdapter(), ACTIVITY)
+ assert context.responded is False
+
+ def test_should_be_able_to_set_responded_to_true(self):
+ context = TurnContext(MockSimpleAdapter(), ACTIVITY)
+ assert context.responded is False
+ context.responded = True
+ assert context.responded
+
+ def test_should_not_be_able_to_set_responded_to_false(self):
+ context = TurnContext(MockSimpleAdapter(), ACTIVITY)
+ try:
+ context.responded = False
+ except ValueError:
+ pass
+ except Exception as error:
+ raise error
+
+ @pytest.mark.asyncio
+ async def test_should_call_on_delete_activity_handlers_before_deletion(self):
+ context = TurnContext(MockSimpleAdapter(), ACTIVITY)
+ called = False
+
+ async def delete_handler(context, reference, next_handler_coroutine):
+ nonlocal called
+ called = True
+ assert reference is not None
+ assert context is not None
+ assert reference.activity_id == "1234"
+ await next_handler_coroutine()
+
+ context.on_delete_activity(delete_handler)
+ await context.delete_activity(ACTIVITY.id)
+ assert called is True
+
+ @pytest.mark.asyncio
+ async def test_should_call_multiple_on_delete_activity_handlers_in_order(self):
+ context = TurnContext(MockSimpleAdapter(), ACTIVITY)
+ called_first = False
+ called_second = False
+
+ async def first_delete_handler(context, reference, next_handler_coroutine):
+ nonlocal called_first, called_second
+ assert (
+ called_first is False
+ ), "called_first should not be True before first_delete_handler is called."
+ called_first = True
+ assert (
+ called_second is False
+ ), "Second on_delete_activity handler was called before first."
+ assert reference is not None
+ assert context is not None
+ assert reference.activity_id == "1234"
+ await next_handler_coroutine()
+
+ async def second_delete_handler(context, reference, next_handler_coroutine):
+ nonlocal called_first, called_second
+ assert called_first
+ assert (
+ called_second is False
+ ), "called_second was set to True before second handler was called."
+ called_second = True
+ assert reference is not None
+ assert context is not None
+ assert reference.activity_id == "1234"
+ await next_handler_coroutine()
+
+ context.on_delete_activity(first_delete_handler)
+ context.on_delete_activity(second_delete_handler)
+ await context.delete_activity(ACTIVITY.id)
+ assert called_first is True
+ assert called_second is True
+
+ @pytest.mark.asyncio
+ async def test_should_call_send_on_activities_handler_before_send(self):
+ context = TurnContext(MockSimpleAdapter(), ACTIVITY)
+ called = False
+
+ async def send_handler(context, activities, next_handler_coroutine):
+ nonlocal called
+ called = True
+ assert activities is not None
+ assert context is not None
+ assert not activities[0].id
+ await next_handler_coroutine()
+
+ context.on_send_activities(send_handler)
+ await context.send_activity(ACTIVITY)
+ assert called is True
+
+ @pytest.mark.asyncio
+ async def test_should_call_on_update_activity_handler_before_update(self):
+ context = TurnContext(MockSimpleAdapter(), ACTIVITY)
+ called = False
+
+ async def update_handler(context, activity, next_handler_coroutine):
+ nonlocal called
+ called = True
+ assert activity is not None
+ assert context is not None
+ assert activity.id == "1234"
+ await next_handler_coroutine()
+
+ context.on_update_activity(update_handler)
+ await context.update_activity(ACTIVITY)
+ assert called is True
+
+ @pytest.mark.asyncio
+ async def test_update_activity_should_apply_conversation_reference(self):
+ activity_id = "activity ID"
+ context = TurnContext(MockSimpleAdapter(), ACTIVITY)
+ called = False
+
+ async def update_handler(context, activity, next_handler_coroutine):
+ nonlocal called
+ called = True
+ assert context is not None
+ assert activity.id == activity_id
+ assert activity.conversation.id == ACTIVITY.conversation.id
+ await next_handler_coroutine()
+
+ context.on_update_activity(update_handler)
+ new_activity = MessageFactory.text("test text")
+ new_activity.id = activity_id
+ update_result = await context.update_activity(new_activity)
+ assert called is True
+ assert update_result.id == activity_id
+
+ def test_get_conversation_reference_should_return_valid_reference(self):
+ reference = ACTIVITY.get_conversation_reference()
+
+ assert reference.activity_id == ACTIVITY.id
+ assert reference.user == ACTIVITY.from_property
+ assert reference.agent == ACTIVITY.recipient
+ assert reference.conversation == ACTIVITY.conversation
+ assert reference.channel_id == ACTIVITY.channel_id
+ assert reference.locale == ACTIVITY.locale
+ assert reference.service_url == ACTIVITY.service_url
+
+ def test_apply_conversation_reference_should_return_prepare_reply_when_is_incoming_is_false(
+ self,
+ ):
+ reference = ACTIVITY.get_conversation_reference()
+ reply = TurnContext.apply_conversation_reference(
+ Activity(type="message", text="reply"), reference
+ )
+
+ assert reply.recipient == ACTIVITY.from_property
+ assert reply.from_property == ACTIVITY.recipient
+ assert reply.conversation == ACTIVITY.conversation
+ assert reply.locale == ACTIVITY.locale
+ assert reply.service_url == ACTIVITY.service_url
+ assert reply.channel_id == ACTIVITY.channel_id
+
+ def test_apply_conversation_reference_when_is_incoming_is_true_should_not_prepare_a_reply(
+ self,
+ ):
+ reference = ACTIVITY.get_conversation_reference()
+ reply = TurnContext.apply_conversation_reference(
+ Activity(type="message", text="reply"), reference, True
+ )
+
+ assert reply.recipient == ACTIVITY.recipient
+ assert reply.from_property == ACTIVITY.from_property
+ assert reply.conversation == ACTIVITY.conversation
+ assert reply.locale == ACTIVITY.locale
+ assert reply.service_url == ACTIVITY.service_url
+ assert reply.channel_id == ACTIVITY.channel_id
+
+ @pytest.mark.asyncio
+ async def test_should_get_conversation_reference_using_get_reply_conversation_reference(
+ self,
+ ):
+ context = TurnContext(MockSimpleAdapter(), ACTIVITY)
+ reply = await context.send_activity("test")
+
+ assert reply is not None
+ assert reply.id, "reply has an id"
+
+ reference = TurnContext.get_reply_conversation_reference(
+ context.activity, reply
+ )
+
+ assert reference.activity_id, "reference has an activity id"
+ assert (
+ reference.activity_id == reply.id
+ ), "reference id matches outgoing reply id"
+
+ def test_should_remove_at_mention_from_activity(self):
+ activity = Activity(
+ type="message",
+ text="TestOAuth619 test activity",
+ recipient=ChannelAccount(id="TestOAuth619"),
+ entities=[
+ Entity(
+ type="mention",
+ text="TestOAuth619",
+ mentioned=ChannelAccount(name="Bot", id="TestOAuth619"),
+ )
+ ],
+ )
+
+ text = TurnContext.remove_recipient_mention(activity)
+
+ assert text == " test activity"
+ assert activity.text == " test activity"
+
+ def test_should_remove_at_mention_with_regex_characters(self):
+ activity = Activity(
+ type="message",
+ text="Test (*.[]$%#^&?) test activity",
+ recipient=ChannelAccount(id="Test (*.[]$%#^&?)"),
+ entities=[
+ Entity(
+ type="mention",
+ text="Test (*.[]$%#^&?)",
+ mentioned=ChannelAccount(name="Bot", id="Test (*.[]$%#^&?)"),
+ )
+ ],
+ )
+
+ text = TurnContext.remove_recipient_mention(activity)
+
+ assert text == " test activity"
+ assert activity.text == " test activity"
+
+ def test_should_remove_custom_mention_from_activity(self):
+ activity = Activity(
+ text="Hallo",
+ text_format="plain",
+ type="message",
+ timestamp="2025-03-11T14:16:47.0093935Z",
+ id="1741702606984",
+ channel_id="msteams",
+ service_url="https://smba.trafficmanager.net/emea/REDACTED/",
+ from_property=ChannelAccount(
+ id="29:1J-K4xVh-sLpdwQ-R5GkOZ_TB0W3ec_37p710aH8qe8bITA0zxdgIGc9l-MdDdkdE_jasSfNOeWXyyL1nsrHtBQ",
+ name="",
+ aad_object_id="REDACTED",
+ ),
+ conversation=ConversationAccount(
+ is_group=True,
+ conversation_type="groupChat",
+ tenant_id="REDACTED",
+ id="19:Ql86tXNM2lTBXNKJdqKdwIF9ltGZwpvluLvnJdA0tmg1@thread.v2",
+ ),
+ recipient=ChannelAccount(
+ id="28:c5d5fb56-a1a4-4467-a7a3-1b37905498a0", name="Azure AI Agent"
+ ),
+ entities=[
+ Entity(
+ type="mention",
+ mentioned=ChannelAccount(
+ id="28:c5d5fb56-a1a4-4467-a7a3-1b37905498a0",
+ name="Custom Agent",
+ ),
+ )
+ ],
+ channel_data={"tenant": {"id": "REDACTED"}, "productContext": "COPILOT"},
+ )
+
+ text = TurnContext.remove_mention_text(activity, activity.recipient.id)
+
+ assert text == "Hallo"
+ assert activity.text == "Hallo"
+
+ @pytest.mark.asyncio
+ async def test_should_send_a_trace_activity(self):
+ context = TurnContext(MockSimpleAdapter(), ACTIVITY)
+ called = False
+
+ # pylint: disable=unused-argument
+ async def aux_func(
+ ctx: TurnContext, activities: List[Activity], next: Callable
+ ):
+ nonlocal called
+ called = True
+ assert isinstance(activities, list), "activities not array."
+ assert len(activities) == 1, "invalid count of activities."
+ assert activities[0].type == ActivityTypes.trace, "type wrong."
+ assert activities[0].name == "name-text", "name wrong."
+ assert activities[0].value == "value-text", "value worng."
+ assert activities[0].value_type == "valueType-text", "valeuType wrong."
+ assert activities[0].label == "label-text", "label wrong."
+ return []
+
+ context.on_send_activities(aux_func)
+ await context.send_trace_activity(
+ "name-text", "value-text", "valueType-text", "label-text"
+ )
+ assert called
From dd38170e3f472ebaffb88a93e0d4c8d17943fb08 Mon Sep 17 00:00:00 2001
From: = <=>
Date: Tue, 15 Jul 2025 13:36:01 -0700
Subject: [PATCH 2/3] fix model to derive from instead of
---
.../microsoft/agents/core/models/mention.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libraries/Core/microsoft-agents-core/microsoft/agents/core/models/mention.py b/libraries/Core/microsoft-agents-core/microsoft/agents/core/models/mention.py
index c96d8d29..d57f6d6b 100644
--- a/libraries/Core/microsoft-agents-core/microsoft/agents/core/models/mention.py
+++ b/libraries/Core/microsoft-agents-core/microsoft/agents/core/models/mention.py
@@ -1,9 +1,9 @@
from .channel_account import ChannelAccount
-from .agents_model import AgentsModel
+from .entity import Entity
from ._type_aliases import NonEmptyString
-class Mention(AgentsModel):
+class Mention(Entity):
"""Mention information (entity type: "mention").
:param mentioned: The mentioned user
From 9d0c307fb6770b3c1c35208c85cc085d96cb1adc Mon Sep 17 00:00:00 2001
From: = <=>
Date: Tue, 15 Jul 2025 13:46:25 -0700
Subject: [PATCH 3/3] fix branches
---
.../tests/test_turn_context.py | 420 ------------------
1 file changed, 420 deletions(-)
delete mode 100644 libraries/Builder/microsoft-agents-builder/tests/test_turn_context.py
diff --git a/libraries/Builder/microsoft-agents-builder/tests/test_turn_context.py b/libraries/Builder/microsoft-agents-builder/tests/test_turn_context.py
deleted file mode 100644
index 8ae8cac2..00000000
--- a/libraries/Builder/microsoft-agents-builder/tests/test_turn_context.py
+++ /dev/null
@@ -1,420 +0,0 @@
-import pytest
-from typing import Callable, List
-
-from microsoft.agents.core.models import (
- Activity,
- ActivityTypes,
- ChannelAccount,
- ConversationAccount,
- Entity,
- Mention,
- ResourceResponse,
-)
-from microsoft.agents.builder import ChannelAdapter, MessageFactory, TurnContext
-
-activity_data = {
- "type": "message",
- "id": "1234",
- "text":"test",
- "from_property": ChannelAccount(id="user", name="User Name"),
- "recipient": ChannelAccount(id="bot", name="Bot Name"),
- "conversation": ConversationAccount(id="convo", name="Convo Name"),
- "channel_id":"UnitTest",
- "locale":"en-uS",
- "service_url":"https://example.org",
-}
-
-ACTIVITY = Activity(**activity_data)
-
-
-class MockSimpleAdapter(ChannelAdapter):
- async def send_activities(self, context, activities) -> List[ResourceResponse]:
- responses = []
- assert context is not None
- assert activities is not None
- assert isinstance(activities, list)
- assert activities
- for idx, activity in enumerate(activities): # pylint: disable=unused-variable
- assert isinstance(activity, Activity)
- assert activity.type == "message" or activity.type == ActivityTypes.trace
- responses.append(ResourceResponse(id="5678"))
- return responses
-
- async def update_activity(self, context, activity):
- assert context is not None
- assert activity is not None
- assert activity.id is not None
- return ResourceResponse(id=activity.id)
-
- async def delete_activity(self, context, reference):
- assert context is not None
- assert reference is not None
- assert reference.activity_id == ACTIVITY.id
-
-
-class TestTurnContext:
- def test_should_create_context_with_request_and_adapter(self):
- TurnContext(MockSimpleAdapter(), ACTIVITY)
-
- def test_should_not_create_context_without_request(self):
- try:
- TurnContext(MockSimpleAdapter(), None)
- except TypeError:
- pass
- except Exception as error:
- raise error
-
- def test_should_not_create_context_without_adapter(self):
- try:
- TurnContext(None, ACTIVITY)
- except TypeError:
- pass
- except Exception as error:
- raise error
-
- def test_should_create_context_with_older_context(self):
- context = TurnContext(MockSimpleAdapter(), ACTIVITY)
- TurnContext(context)
-
- def test_copy_to_should_copy_all_references(self):
- # pylint: disable=protected-access
- old_adapter = MockSimpleAdapter()
- old_activity = Activity(id="2", type="message", text="test copy")
- old_context = TurnContext(old_adapter, old_activity)
- old_context.responded = True
-
- async def send_activities_handler(context, activities, next_handler):
- assert context is not None
- assert activities is not None
- assert next_handler is not None
- await next_handler
-
- async def delete_activity_handler(context, reference, next_handler):
- assert context is not None
- assert reference is not None
- assert next_handler is not None
- await next_handler
-
- async def update_activity_handler(context, activity, next_handler):
- assert context is not None
- assert activity is not None
- assert next_handler is not None
- await next_handler
-
- old_context.on_send_activities(send_activities_handler)
- old_context.on_delete_activity(delete_activity_handler)
- old_context.on_update_activity(update_activity_handler)
-
- adapter = MockSimpleAdapter()
- new_context = TurnContext(adapter, ACTIVITY)
- assert not new_context._on_send_activities # pylint: disable=protected-access
- assert not new_context._on_update_activity # pylint: disable=protected-access
- assert not new_context._on_delete_activity # pylint: disable=protected-access
-
- old_context.copy_to(new_context)
-
- assert new_context.adapter == old_adapter
- assert new_context.activity == old_activity
- assert new_context.responded is True
- assert (
- len(new_context._on_send_activities) == 1
- ) # pylint: disable=protected-access
- assert (
- len(new_context._on_update_activity) == 1
- ) # pylint: disable=protected-access
- assert (
- len(new_context._on_delete_activity) == 1
- ) # pylint: disable=protected-access
-
- def test_responded_should_be_automatically_set_to_false(self):
- context = TurnContext(MockSimpleAdapter(), ACTIVITY)
- assert context.responded is False
-
- def test_should_be_able_to_set_responded_to_true(self):
- context = TurnContext(MockSimpleAdapter(), ACTIVITY)
- assert context.responded is False
- context.responded = True
- assert context.responded
-
- def test_should_not_be_able_to_set_responded_to_false(self):
- context = TurnContext(MockSimpleAdapter(), ACTIVITY)
- try:
- context.responded = False
- except ValueError:
- pass
- except Exception as error:
- raise error
-
- @pytest.mark.asyncio
- async def test_should_call_on_delete_activity_handlers_before_deletion(self):
- context = TurnContext(MockSimpleAdapter(), ACTIVITY)
- called = False
-
- async def delete_handler(context, reference, next_handler_coroutine):
- nonlocal called
- called = True
- assert reference is not None
- assert context is not None
- assert reference.activity_id == "1234"
- await next_handler_coroutine()
-
- context.on_delete_activity(delete_handler)
- await context.delete_activity(ACTIVITY.id)
- assert called is True
-
- @pytest.mark.asyncio
- async def test_should_call_multiple_on_delete_activity_handlers_in_order(self):
- context = TurnContext(MockSimpleAdapter(), ACTIVITY)
- called_first = False
- called_second = False
-
- async def first_delete_handler(context, reference, next_handler_coroutine):
- nonlocal called_first, called_second
- assert (
- called_first is False
- ), "called_first should not be True before first_delete_handler is called."
- called_first = True
- assert (
- called_second is False
- ), "Second on_delete_activity handler was called before first."
- assert reference is not None
- assert context is not None
- assert reference.activity_id == "1234"
- await next_handler_coroutine()
-
- async def second_delete_handler(context, reference, next_handler_coroutine):
- nonlocal called_first, called_second
- assert called_first
- assert (
- called_second is False
- ), "called_second was set to True before second handler was called."
- called_second = True
- assert reference is not None
- assert context is not None
- assert reference.activity_id == "1234"
- await next_handler_coroutine()
-
- context.on_delete_activity(first_delete_handler)
- context.on_delete_activity(second_delete_handler)
- await context.delete_activity(ACTIVITY.id)
- assert called_first is True
- assert called_second is True
-
- @pytest.mark.asyncio
- async def test_should_call_send_on_activities_handler_before_send(self):
- context = TurnContext(MockSimpleAdapter(), ACTIVITY)
- called = False
-
- async def send_handler(context, activities, next_handler_coroutine):
- nonlocal called
- called = True
- assert activities is not None
- assert context is not None
- assert not activities[0].id
- await next_handler_coroutine()
-
- context.on_send_activities(send_handler)
- await context.send_activity(ACTIVITY)
- assert called is True
-
- @pytest.mark.asyncio
- async def test_should_call_on_update_activity_handler_before_update(self):
- context = TurnContext(MockSimpleAdapter(), ACTIVITY)
- called = False
-
- async def update_handler(context, activity, next_handler_coroutine):
- nonlocal called
- called = True
- assert activity is not None
- assert context is not None
- assert activity.id == "1234"
- await next_handler_coroutine()
-
- context.on_update_activity(update_handler)
- await context.update_activity(ACTIVITY)
- assert called is True
-
- @pytest.mark.asyncio
- async def test_update_activity_should_apply_conversation_reference(self):
- activity_id = "activity ID"
- context = TurnContext(MockSimpleAdapter(), ACTIVITY)
- called = False
-
- async def update_handler(context, activity, next_handler_coroutine):
- nonlocal called
- called = True
- assert context is not None
- assert activity.id == activity_id
- assert activity.conversation.id == ACTIVITY.conversation.id
- await next_handler_coroutine()
-
- context.on_update_activity(update_handler)
- new_activity = MessageFactory.text("test text")
- new_activity.id = activity_id
- update_result = await context.update_activity(new_activity)
- assert called is True
- assert update_result.id == activity_id
-
- def test_get_conversation_reference_should_return_valid_reference(self):
- reference = ACTIVITY.get_conversation_reference()
-
- assert reference.activity_id == ACTIVITY.id
- assert reference.user == ACTIVITY.from_property
- assert reference.agent == ACTIVITY.recipient
- assert reference.conversation == ACTIVITY.conversation
- assert reference.channel_id == ACTIVITY.channel_id
- assert reference.locale == ACTIVITY.locale
- assert reference.service_url == ACTIVITY.service_url
-
- def test_apply_conversation_reference_should_return_prepare_reply_when_is_incoming_is_false(
- self,
- ):
- reference = ACTIVITY.get_conversation_reference()
- reply = TurnContext.apply_conversation_reference(
- Activity(type="message", text="reply"), reference
- )
-
- assert reply.recipient == ACTIVITY.from_property
- assert reply.from_property == ACTIVITY.recipient
- assert reply.conversation == ACTIVITY.conversation
- assert reply.locale == ACTIVITY.locale
- assert reply.service_url == ACTIVITY.service_url
- assert reply.channel_id == ACTIVITY.channel_id
-
- def test_apply_conversation_reference_when_is_incoming_is_true_should_not_prepare_a_reply(
- self,
- ):
- reference = ACTIVITY.get_conversation_reference()
- reply = TurnContext.apply_conversation_reference(
- Activity(type="message", text="reply"), reference, True
- )
-
- assert reply.recipient == ACTIVITY.recipient
- assert reply.from_property == ACTIVITY.from_property
- assert reply.conversation == ACTIVITY.conversation
- assert reply.locale == ACTIVITY.locale
- assert reply.service_url == ACTIVITY.service_url
- assert reply.channel_id == ACTIVITY.channel_id
-
- @pytest.mark.asyncio
- async def test_should_get_conversation_reference_using_get_reply_conversation_reference(
- self,
- ):
- context = TurnContext(MockSimpleAdapter(), ACTIVITY)
- reply = await context.send_activity("test")
-
- assert reply is not None
- assert reply.id, "reply has an id"
-
- reference = TurnContext.get_reply_conversation_reference(
- context.activity, reply
- )
-
- assert reference.activity_id, "reference has an activity id"
- assert (
- reference.activity_id == reply.id
- ), "reference id matches outgoing reply id"
-
- def test_should_remove_at_mention_from_activity(self):
- activity = Activity(
- type="message",
- text="TestOAuth619 test activity",
- recipient=ChannelAccount(id="TestOAuth619"),
- entities=[
- Entity(
- type="mention",
- text="TestOAuth619",
- mentioned=ChannelAccount(name="Bot", id="TestOAuth619"),
- )
- ],
- )
-
- text = TurnContext.remove_recipient_mention(activity)
-
- assert text == " test activity"
- assert activity.text == " test activity"
-
- def test_should_remove_at_mention_with_regex_characters(self):
- activity = Activity(
- type="message",
- text="Test (*.[]$%#^&?) test activity",
- recipient=ChannelAccount(id="Test (*.[]$%#^&?)"),
- entities=[
- Entity(
- type="mention",
- text="Test (*.[]$%#^&?)",
- mentioned=ChannelAccount(name="Bot", id="Test (*.[]$%#^&?)"),
- )
- ],
- )
-
- text = TurnContext.remove_recipient_mention(activity)
-
- assert text == " test activity"
- assert activity.text == " test activity"
-
- def test_should_remove_custom_mention_from_activity(self):
- activity = Activity(
- text="Hallo",
- text_format="plain",
- type="message",
- timestamp="2025-03-11T14:16:47.0093935Z",
- id="1741702606984",
- channel_id="msteams",
- service_url="https://smba.trafficmanager.net/emea/REDACTED/",
- from_property=ChannelAccount(
- id="29:1J-K4xVh-sLpdwQ-R5GkOZ_TB0W3ec_37p710aH8qe8bITA0zxdgIGc9l-MdDdkdE_jasSfNOeWXyyL1nsrHtBQ",
- name="",
- aad_object_id="REDACTED",
- ),
- conversation=ConversationAccount(
- is_group=True,
- conversation_type="groupChat",
- tenant_id="REDACTED",
- id="19:Ql86tXNM2lTBXNKJdqKdwIF9ltGZwpvluLvnJdA0tmg1@thread.v2",
- ),
- recipient=ChannelAccount(
- id="28:c5d5fb56-a1a4-4467-a7a3-1b37905498a0", name="Azure AI Agent"
- ),
- entities=[
- Entity(
- type="mention",
- mentioned=ChannelAccount(
- id="28:c5d5fb56-a1a4-4467-a7a3-1b37905498a0",
- name="Custom Agent",
- ),
- )
- ],
- channel_data={"tenant": {"id": "REDACTED"}, "productContext": "COPILOT"},
- )
-
- text = TurnContext.remove_mention_text(activity, activity.recipient.id)
-
- assert text == "Hallo"
- assert activity.text == "Hallo"
-
- @pytest.mark.asyncio
- async def test_should_send_a_trace_activity(self):
- context = TurnContext(MockSimpleAdapter(), ACTIVITY)
- called = False
-
- # pylint: disable=unused-argument
- async def aux_func(
- ctx: TurnContext, activities: List[Activity], next: Callable
- ):
- nonlocal called
- called = True
- assert isinstance(activities, list), "activities not array."
- assert len(activities) == 1, "invalid count of activities."
- assert activities[0].type == ActivityTypes.trace, "type wrong."
- assert activities[0].name == "name-text", "name wrong."
- assert activities[0].value == "value-text", "value worng."
- assert activities[0].value_type == "valueType-text", "valeuType wrong."
- assert activities[0].label == "label-text", "label wrong."
- return []
-
- context.on_send_activities(aux_func)
- await context.send_trace_activity(
- "name-text", "value-text", "valueType-text", "label-text"
- )
- assert called