We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Remove Mention Support
**Describe the solution you'd like**
Add Remove Mention support as JS and C#.  See ActivityExtensions for a reference of Mention related methods.  To remove mentions from Activity.Text, see ActivityExtensions.RemoveMentionText and ActivityExtensions.RemoveRecipientMention.  Note that in JS it is TurnContext.removeMentionText.

**Describe alternatives you've considered**
None

**Additional context**
I have implemented SkypeMentionNormalizeMiddleware on all platforms to correct Skype mentions.  The user could still make use of this middleware, but would have to manually remove the mention from Activity.Text to have the same functionality as the other platforms.

[enhancement]


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `libraries/botbuilder-core/botbuilder/core/turn_context.py`
Content:
```
1 # Copyright (c) Microsoft Corporation. All rights reserved.
2 # Licensed under the MIT License.
3 
4 from copy import copy
5 from typing import List, Callable, Union, Dict
6 from botbuilder.schema import Activity, ConversationReference, ResourceResponse
7 
8 
9 class TurnContext:
10     def __init__(self, adapter_or_context, request: Activity = None):
11         """
12         Creates a new TurnContext instance.
13         :param adapter_or_context:
14         :param request:
15         """
16         if isinstance(adapter_or_context, TurnContext):
17             adapter_or_context.copy_to(self)
18         else:
19             self.adapter = adapter_or_context
20             self._activity = request
21             self.responses: List[Activity] = []
22             self._services: dict = {}
23             self._on_send_activities: Callable[
24                 ["TurnContext", List[Activity], Callable], List[ResourceResponse]
25             ] = []
26             self._on_update_activity: Callable[
27                 ["TurnContext", Activity, Callable], ResourceResponse
28             ] = []
29             self._on_delete_activity: Callable[
30                 ["TurnContext", ConversationReference, Callable], None
31             ] = []
32             self._responded: bool = False
33 
34         if self.adapter is None:
35             raise TypeError("TurnContext must be instantiated with an adapter.")
36         if self.activity is None:
37             raise TypeError(
38                 "TurnContext must be instantiated with a request parameter of type Activity."
39             )
40 
41         self._turn_state = {}
42 
43     @property
44     def turn_state(self) -> Dict[str, object]:
45         return self._turn_state
46 
47     def copy_to(self, context: "TurnContext") -> None:
48         """
49         Called when this TurnContext instance is passed into the constructor of a new TurnContext
50         instance. Can be overridden in derived classes.
51         :param context:
52         :return:
53         """
54         for attribute in [
55             "adapter",
56             "activity",
57             "_responded",
58             "_services",
59             "_on_send_activities",
60             "_on_update_activity",
61             "_on_delete_activity",
62         ]:
63             setattr(context, attribute, getattr(self, attribute))
64 
65     @property
66     def activity(self):
67         """
68         The received activity.
69         :return:
70         """
71         return self._activity
72 
73     @activity.setter
74     def activity(self, value):
75         """
76         Used to set TurnContext._activity when a context object is created. Only takes instances of Activities.
77         :param value:
78         :return:
79         """
80         if not isinstance(value, Activity):
81             raise TypeError(
82                 "TurnContext: cannot set `activity` to a type other than Activity."
83             )
84         self._activity = value
85 
86     @property
87     def responded(self) -> bool:
88         """
89         If `true` at least one response has been sent for the current turn of conversation.
90         :return:
91         """
92         return self._responded
93 
94     @responded.setter
95     def responded(self, value: bool):
96         if not value:
97             raise ValueError("TurnContext: cannot set TurnContext.responded to False.")
98         self._responded = True
99 
100     @property
101     def services(self):
102         """
103         Map of services and other values cached for the lifetime of the turn.
104         :return:
105         """
106         return self._services
107 
108     def get(self, key: str) -> object:
109         if not key or not isinstance(key, str):
110             raise TypeError('"key" must be a valid string.')
111         try:
112             return self._services[key]
113         except KeyError:
114             raise KeyError("%s not found in TurnContext._services." % key)
115 
116     def has(self, key: str) -> bool:
117         """
118         Returns True is set() has been called for a key. The cached value may be of type 'None'.
119         :param key:
120         :return:
121         """
122         if key in self._services:
123             return True
124         return False
125 
126     def set(self, key: str, value: object) -> None:
127         """
128         Caches a value for the lifetime of the current turn.
129         :param key:
130         :param value:
131         :return:
132         """
133         if not key or not isinstance(key, str):
134             raise KeyError('"key" must be a valid string.')
135 
136         self._services[key] = value
137 
138     async def send_activity(
139         self, *activity_or_text: Union[Activity, str]
140     ) -> ResourceResponse:
141         """
142         Sends a single activity or message to the user.
143         :param activity_or_text:
144         :return:
145         """
146         reference = TurnContext.get_conversation_reference(self.activity)
147 
148         output = [
149             TurnContext.apply_conversation_reference(
150                 Activity(text=a, type="message") if isinstance(a, str) else a, reference
151             )
152             for a in activity_or_text
153         ]
154         for activity in output:
155             if not activity.input_hint:
156                 activity.input_hint = "acceptingInput"
157 
158         async def callback(context: "TurnContext", output):
159             responses = await context.adapter.send_activities(context, output)
160             context._responded = True  # pylint: disable=protected-access
161             return responses
162 
163         result = await self._emit(
164             self._on_send_activities, output, callback(self, output)
165         )
166 
167         return result[0] if result else ResourceResponse()
168 
169     async def update_activity(self, activity: Activity):
170         """
171         Replaces an existing activity.
172         :param activity:
173         :return:
174         """
175         return await self._emit(
176             self._on_update_activity,
177             activity,
178             self.adapter.update_activity(self, activity),
179         )
180 
181     async def delete_activity(self, id_or_reference: Union[str, ConversationReference]):
182         """
183         Deletes an existing activity.
184         :param id_or_reference:
185         :return:
186         """
187         if isinstance(id_or_reference, str):
188             reference = TurnContext.get_conversation_reference(self.activity)
189             reference.activity_id = id_or_reference
190         else:
191             reference = id_or_reference
192         return await self._emit(
193             self._on_delete_activity,
194             reference,
195             self.adapter.delete_activity(self, reference),
196         )
197 
198     def on_send_activities(self, handler) -> "TurnContext":
199         """
200         Registers a handler to be notified of and potentially intercept the sending of activities.
201         :param handler:
202         :return:
203         """
204         self._on_send_activities.append(handler)
205         return self
206 
207     def on_update_activity(self, handler) -> "TurnContext":
208         """
209         Registers a handler to be notified of and potentially intercept an activity being updated.
210         :param handler:
211         :return:
212         """
213         self._on_update_activity.append(handler)
214         return self
215 
216     def on_delete_activity(self, handler) -> "TurnContext":
217         """
218         Registers a handler to be notified of and potentially intercept an activity being deleted.
219         :param handler:
220         :return:
221         """
222         self._on_delete_activity.append(handler)
223         return self
224 
225     async def _emit(self, plugins, arg, logic):
226         handlers = copy(plugins)
227 
228         async def emit_next(i: int):
229             context = self
230             try:
231                 if i < len(handlers):
232 
233                     async def next_handler():
234                         await emit_next(i + 1)
235 
236                     await handlers[i](context, arg, next_handler)
237 
238             except Exception as error:
239                 raise error
240 
241         await emit_next(0)
242         # This should be changed to `return await logic()`
243         return await logic
244 
245     @staticmethod
246     def get_conversation_reference(activity: Activity) -> ConversationReference:
247         """
248         Returns the conversation reference for an activity. This can be saved as a plain old JSON
249         object and then later used to message the user proactively.
250 
251         Usage Example:
252         reference = TurnContext.get_conversation_reference(context.request)
253         :param activity:
254         :return:
255         """
256         return ConversationReference(
257             activity_id=activity.id,
258             user=copy(activity.from_property),
259             bot=copy(activity.recipient),
260             conversation=copy(activity.conversation),
261             channel_id=activity.channel_id,
262             service_url=activity.service_url,
263         )
264 
265     @staticmethod
266     def apply_conversation_reference(
267         activity: Activity, reference: ConversationReference, is_incoming: bool = False
268     ) -> Activity:
269         """
270         Updates an activity with the delivery information from a conversation reference. Calling
271         this after get_conversation_reference on an incoming activity
272         will properly address the reply to a received activity.
273         :param activity:
274         :param reference:
275         :param is_incoming:
276         :return:
277         """
278         activity.channel_id = reference.channel_id
279         activity.service_url = reference.service_url
280         activity.conversation = reference.conversation
281         if is_incoming:
282             activity.from_property = reference.user
283             activity.recipient = reference.bot
284             if reference.activity_id:
285                 activity.id = reference.activity_id
286         else:
287             activity.from_property = reference.bot
288             activity.recipient = reference.user
289             if reference.activity_id:
290                 activity.reply_to_id = reference.activity_id
291 
292         return activity
293
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/libraries/botbuilder-core/botbuilder/core/turn_context.py b/libraries/botbuilder-core/botbuilder/core/turn_context.py
--- a/libraries/botbuilder-core/botbuilder/core/turn_context.py
+++ b/libraries/botbuilder-core/botbuilder/core/turn_context.py
@@ -1,9 +1,10 @@
 # Copyright (c) Microsoft Corporation. All rights reserved.
 # Licensed under the MIT License.
 
+import re
 from copy import copy
 from typing import List, Callable, Union, Dict
-from botbuilder.schema import Activity, ConversationReference, ResourceResponse
+from botbuilder.schema import Activity, ConversationReference, Mention, ResourceResponse
 
 
 class TurnContext:
@@ -290,3 +291,44 @@
                 activity.reply_to_id = reference.activity_id
 
         return activity
+
+    @staticmethod
+    def get_reply_conversation_reference(
+        activity: Activity, reply: ResourceResponse
+    ) -> ConversationReference:
+        reference: ConversationReference = TurnContext.get_conversation_reference(
+            activity
+        )
+
+        # Update the reference with the new outgoing Activity's id.
+        reference.activity_id = reply.id
+
+        return reference
+
+    @staticmethod
+    def remove_recipient_mention(activity: Activity) -> str:
+        return TurnContext.remove_mention_text(activity, activity.recipient.id)
+
+    @staticmethod
+    def remove_mention_text(activity: Activity, identifier: str) -> str:
+        mentions = TurnContext.get_mentions(activity)
+        for mention in mentions:
+            if mention.mentioned.id == identifier:
+                mention_name_match = re.match(
+                    r"<at(.*)>(.*?)<\/at>", mention.text, re.IGNORECASE
+                )
+                if mention_name_match:
+                    activity.text = re.sub(
+                        mention_name_match.groups()[1], "", activity.text
+                    )
+                    activity.text = re.sub(r"<at><\/at>", "", activity.text)
+        return activity.text
+
+    @staticmethod
+    def get_mentions(activity: Activity) -> List[Mention]:
+        result: List[Mention] = []
+        if activity.entities is not None:
+            for entity in activity.entities:
+                if entity.type.lower() == "mention":
+                    result.append(entity)
+        return result

{"golden_diff": "diff --git a/libraries/botbuilder-core/botbuilder/core/turn_context.py b/libraries/botbuilder-core/botbuilder/core/turn_context.py\n--- a/libraries/botbuilder-core/botbuilder/core/turn_context.py\n+++ b/libraries/botbuilder-core/botbuilder/core/turn_context.py\n@@ -1,9 +1,10 @@\n # Copyright (c) Microsoft Corporation. All rights reserved.\n # Licensed under the MIT License.\n \n+import re\n from copy import copy\n from typing import List, Callable, Union, Dict\n-from botbuilder.schema import Activity, ConversationReference, ResourceResponse\n+from botbuilder.schema import Activity, ConversationReference, Mention, ResourceResponse\n \n \n class TurnContext:\n@@ -290,3 +291,44 @@\n                 activity.reply_to_id = reference.activity_id\n \n         return activity\n+\n+    @staticmethod\n+    def get_reply_conversation_reference(\n+        activity: Activity, reply: ResourceResponse\n+    ) -> ConversationReference:\n+        reference: ConversationReference = TurnContext.get_conversation_reference(\n+            activity\n+        )\n+\n+        # Update the reference with the new outgoing Activity's id.\n+        reference.activity_id = reply.id\n+\n+        return reference\n+\n+    @staticmethod\n+    def remove_recipient_mention(activity: Activity) -> str:\n+        return TurnContext.remove_mention_text(activity, activity.recipient.id)\n+\n+    @staticmethod\n+    def remove_mention_text(activity: Activity, identifier: str) -> str:\n+        mentions = TurnContext.get_mentions(activity)\n+        for mention in mentions:\n+            if mention.mentioned.id == identifier:\n+                mention_name_match = re.match(\n+                    r\"<at(.*)>(.*?)<\\/at>\", mention.text, re.IGNORECASE\n+                )\n+                if mention_name_match:\n+                    activity.text = re.sub(\n+                        mention_name_match.groups()[1], \"\", activity.text\n+                    )\n+                    activity.text = re.sub(r\"<at><\\/at>\", \"\", activity.text)\n+        return activity.text\n+\n+    @staticmethod\n+    def get_mentions(activity: Activity) -> List[Mention]:\n+        result: List[Mention] = []\n+        if activity.entities is not None:\n+            for entity in activity.entities:\n+                if entity.type.lower() == \"mention\":\n+                    result.append(entity)\n+        return result\n", "issue": "Remove Mention Support\n**Describe the solution you'd like**\r\nAdd Remove Mention support as JS and C#.  See ActivityExtensions for a reference of Mention related methods.  To remove mentions from Activity.Text, see ActivityExtensions.RemoveMentionText and ActivityExtensions.RemoveRecipientMention.  Note that in JS it is TurnContext.removeMentionText.\r\n\r\n**Describe alternatives you've considered**\r\nNone\r\n\r\n**Additional context**\r\nI have implemented SkypeMentionNormalizeMiddleware on all platforms to correct Skype mentions.  The user could still make use of this middleware, but would have to manually remove the mention from Activity.Text to have the same functionality as the other platforms.\r\n\r\n[enhancement]\r\n\n", "before_files": [{"content": "# Copyright (c) Microsoft Corporation. All rights reserved.\n# Licensed under the MIT License.\n\nfrom copy import copy\nfrom typing import List, Callable, Union, Dict\nfrom botbuilder.schema import Activity, ConversationReference, ResourceResponse\n\n\nclass TurnContext:\n    def __init__(self, adapter_or_context, request: Activity = None):\n        \"\"\"\n        Creates a new TurnContext instance.\n        :param adapter_or_context:\n        :param request:\n        \"\"\"\n        if isinstance(adapter_or_context, TurnContext):\n            adapter_or_context.copy_to(self)\n        else:\n            self.adapter = adapter_or_context\n            self._activity = request\n            self.responses: List[Activity] = []\n            self._services: dict = {}\n            self._on_send_activities: Callable[\n                [\"TurnContext\", List[Activity], Callable], List[ResourceResponse]\n            ] = []\n            self._on_update_activity: Callable[\n                [\"TurnContext\", Activity, Callable], ResourceResponse\n            ] = []\n            self._on_delete_activity: Callable[\n                [\"TurnContext\", ConversationReference, Callable], None\n            ] = []\n            self._responded: bool = False\n\n        if self.adapter is None:\n            raise TypeError(\"TurnContext must be instantiated with an adapter.\")\n        if self.activity is None:\n            raise TypeError(\n                \"TurnContext must be instantiated with a request parameter of type Activity.\"\n            )\n\n        self._turn_state = {}\n\n    @property\n    def turn_state(self) -> Dict[str, object]:\n        return self._turn_state\n\n    def copy_to(self, context: \"TurnContext\") -> None:\n        \"\"\"\n        Called when this TurnContext instance is passed into the constructor of a new TurnContext\n        instance. Can be overridden in derived classes.\n        :param context:\n        :return:\n        \"\"\"\n        for attribute in [\n            \"adapter\",\n            \"activity\",\n            \"_responded\",\n            \"_services\",\n            \"_on_send_activities\",\n            \"_on_update_activity\",\n            \"_on_delete_activity\",\n        ]:\n            setattr(context, attribute, getattr(self, attribute))\n\n    @property\n    def activity(self):\n        \"\"\"\n        The received activity.\n        :return:\n        \"\"\"\n        return self._activity\n\n    @activity.setter\n    def activity(self, value):\n        \"\"\"\n        Used to set TurnContext._activity when a context object is created. Only takes instances of Activities.\n        :param value:\n        :return:\n        \"\"\"\n        if not isinstance(value, Activity):\n            raise TypeError(\n                \"TurnContext: cannot set `activity` to a type other than Activity.\"\n            )\n        self._activity = value\n\n    @property\n    def responded(self) -> bool:\n        \"\"\"\n        If `true` at least one response has been sent for the current turn of conversation.\n        :return:\n        \"\"\"\n        return self._responded\n\n    @responded.setter\n    def responded(self, value: bool):\n        if not value:\n            raise ValueError(\"TurnContext: cannot set TurnContext.responded to False.\")\n        self._responded = True\n\n    @property\n    def services(self):\n        \"\"\"\n        Map of services and other values cached for the lifetime of the turn.\n        :return:\n        \"\"\"\n        return self._services\n\n    def get(self, key: str) -> object:\n        if not key or not isinstance(key, str):\n            raise TypeError('\"key\" must be a valid string.')\n        try:\n            return self._services[key]\n        except KeyError:\n            raise KeyError(\"%s not found in TurnContext._services.\" % key)\n\n    def has(self, key: str) -> bool:\n        \"\"\"\n        Returns True is set() has been called for a key. The cached value may be of type 'None'.\n        :param key:\n        :return:\n        \"\"\"\n        if key in self._services:\n            return True\n        return False\n\n    def set(self, key: str, value: object) -> None:\n        \"\"\"\n        Caches a value for the lifetime of the current turn.\n        :param key:\n        :param value:\n        :return:\n        \"\"\"\n        if not key or not isinstance(key, str):\n            raise KeyError('\"key\" must be a valid string.')\n\n        self._services[key] = value\n\n    async def send_activity(\n        self, *activity_or_text: Union[Activity, str]\n    ) -> ResourceResponse:\n        \"\"\"\n        Sends a single activity or message to the user.\n        :param activity_or_text:\n        :return:\n        \"\"\"\n        reference = TurnContext.get_conversation_reference(self.activity)\n\n        output = [\n            TurnContext.apply_conversation_reference(\n                Activity(text=a, type=\"message\") if isinstance(a, str) else a, reference\n            )\n            for a in activity_or_text\n        ]\n        for activity in output:\n            if not activity.input_hint:\n                activity.input_hint = \"acceptingInput\"\n\n        async def callback(context: \"TurnContext\", output):\n            responses = await context.adapter.send_activities(context, output)\n            context._responded = True  # pylint: disable=protected-access\n            return responses\n\n        result = await self._emit(\n            self._on_send_activities, output, callback(self, output)\n        )\n\n        return result[0] if result else ResourceResponse()\n\n    async def update_activity(self, activity: Activity):\n        \"\"\"\n        Replaces an existing activity.\n        :param activity:\n        :return:\n        \"\"\"\n        return await self._emit(\n            self._on_update_activity,\n            activity,\n            self.adapter.update_activity(self, activity),\n        )\n\n    async def delete_activity(self, id_or_reference: Union[str, ConversationReference]):\n        \"\"\"\n        Deletes an existing activity.\n        :param id_or_reference:\n        :return:\n        \"\"\"\n        if isinstance(id_or_reference, str):\n            reference = TurnContext.get_conversation_reference(self.activity)\n            reference.activity_id = id_or_reference\n        else:\n            reference = id_or_reference\n        return await self._emit(\n            self._on_delete_activity,\n            reference,\n            self.adapter.delete_activity(self, reference),\n        )\n\n    def on_send_activities(self, handler) -> \"TurnContext\":\n        \"\"\"\n        Registers a handler to be notified of and potentially intercept the sending of activities.\n        :param handler:\n        :return:\n        \"\"\"\n        self._on_send_activities.append(handler)\n        return self\n\n    def on_update_activity(self, handler) -> \"TurnContext\":\n        \"\"\"\n        Registers a handler to be notified of and potentially intercept an activity being updated.\n        :param handler:\n        :return:\n        \"\"\"\n        self._on_update_activity.append(handler)\n        return self\n\n    def on_delete_activity(self, handler) -> \"TurnContext\":\n        \"\"\"\n        Registers a handler to be notified of and potentially intercept an activity being deleted.\n        :param handler:\n        :return:\n        \"\"\"\n        self._on_delete_activity.append(handler)\n        return self\n\n    async def _emit(self, plugins, arg, logic):\n        handlers = copy(plugins)\n\n        async def emit_next(i: int):\n            context = self\n            try:\n                if i < len(handlers):\n\n                    async def next_handler():\n                        await emit_next(i + 1)\n\n                    await handlers[i](context, arg, next_handler)\n\n            except Exception as error:\n                raise error\n\n        await emit_next(0)\n        # This should be changed to `return await logic()`\n        return await logic\n\n    @staticmethod\n    def get_conversation_reference(activity: Activity) -> ConversationReference:\n        \"\"\"\n        Returns the conversation reference for an activity. This can be saved as a plain old JSON\n        object and then later used to message the user proactively.\n\n        Usage Example:\n        reference = TurnContext.get_conversation_reference(context.request)\n        :param activity:\n        :return:\n        \"\"\"\n        return ConversationReference(\n            activity_id=activity.id,\n            user=copy(activity.from_property),\n            bot=copy(activity.recipient),\n            conversation=copy(activity.conversation),\n            channel_id=activity.channel_id,\n            service_url=activity.service_url,\n        )\n\n    @staticmethod\n    def apply_conversation_reference(\n        activity: Activity, reference: ConversationReference, is_incoming: bool = False\n    ) -> Activity:\n        \"\"\"\n        Updates an activity with the delivery information from a conversation reference. Calling\n        this after get_conversation_reference on an incoming activity\n        will properly address the reply to a received activity.\n        :param activity:\n        :param reference:\n        :param is_incoming:\n        :return:\n        \"\"\"\n        activity.channel_id = reference.channel_id\n        activity.service_url = reference.service_url\n        activity.conversation = reference.conversation\n        if is_incoming:\n            activity.from_property = reference.user\n            activity.recipient = reference.bot\n            if reference.activity_id:\n                activity.id = reference.activity_id\n        else:\n            activity.from_property = reference.bot\n            activity.recipient = reference.user\n            if reference.activity_id:\n                activity.reply_to_id = reference.activity_id\n\n        return activity\n", "path": "libraries/botbuilder-core/botbuilder/core/turn_context.py"}], "after_files": [{"content": "# Copyright (c) Microsoft Corporation. All rights reserved.\n# Licensed under the MIT License.\n\nimport re\nfrom copy import copy\nfrom typing import List, Callable, Union, Dict\nfrom botbuilder.schema import Activity, ConversationReference, Mention, ResourceResponse\n\n\nclass TurnContext:\n    def __init__(self, adapter_or_context, request: Activity = None):\n        \"\"\"\n        Creates a new TurnContext instance.\n        :param adapter_or_context:\n        :param request:\n        \"\"\"\n        if isinstance(adapter_or_context, TurnContext):\n            adapter_or_context.copy_to(self)\n        else:\n            self.adapter = adapter_or_context\n            self._activity = request\n            self.responses: List[Activity] = []\n            self._services: dict = {}\n            self._on_send_activities: Callable[\n                [\"TurnContext\", List[Activity], Callable], List[ResourceResponse]\n            ] = []\n            self._on_update_activity: Callable[\n                [\"TurnContext\", Activity, Callable], ResourceResponse\n            ] = []\n            self._on_delete_activity: Callable[\n                [\"TurnContext\", ConversationReference, Callable], None\n            ] = []\n            self._responded: bool = False\n\n        if self.adapter is None:\n            raise TypeError(\"TurnContext must be instantiated with an adapter.\")\n        if self.activity is None:\n            raise TypeError(\n                \"TurnContext must be instantiated with a request parameter of type Activity.\"\n            )\n\n        self._turn_state = {}\n\n    @property\n    def turn_state(self) -> Dict[str, object]:\n        return self._turn_state\n\n    def copy_to(self, context: \"TurnContext\") -> None:\n        \"\"\"\n        Called when this TurnContext instance is passed into the constructor of a new TurnContext\n        instance. Can be overridden in derived classes.\n        :param context:\n        :return:\n        \"\"\"\n        for attribute in [\n            \"adapter\",\n            \"activity\",\n            \"_responded\",\n            \"_services\",\n            \"_on_send_activities\",\n            \"_on_update_activity\",\n            \"_on_delete_activity\",\n        ]:\n            setattr(context, attribute, getattr(self, attribute))\n\n    @property\n    def activity(self):\n        \"\"\"\n        The received activity.\n        :return:\n        \"\"\"\n        return self._activity\n\n    @activity.setter\n    def activity(self, value):\n        \"\"\"\n        Used to set TurnContext._activity when a context object is created. Only takes instances of Activities.\n        :param value:\n        :return:\n        \"\"\"\n        if not isinstance(value, Activity):\n            raise TypeError(\n                \"TurnContext: cannot set `activity` to a type other than Activity.\"\n            )\n        self._activity = value\n\n    @property\n    def responded(self) -> bool:\n        \"\"\"\n        If `true` at least one response has been sent for the current turn of conversation.\n        :return:\n        \"\"\"\n        return self._responded\n\n    @responded.setter\n    def responded(self, value: bool):\n        if not value:\n            raise ValueError(\"TurnContext: cannot set TurnContext.responded to False.\")\n        self._responded = True\n\n    @property\n    def services(self):\n        \"\"\"\n        Map of services and other values cached for the lifetime of the turn.\n        :return:\n        \"\"\"\n        return self._services\n\n    def get(self, key: str) -> object:\n        if not key or not isinstance(key, str):\n            raise TypeError('\"key\" must be a valid string.')\n        try:\n            return self._services[key]\n        except KeyError:\n            raise KeyError(\"%s not found in TurnContext._services.\" % key)\n\n    def has(self, key: str) -> bool:\n        \"\"\"\n        Returns True is set() has been called for a key. The cached value may be of type 'None'.\n        :param key:\n        :return:\n        \"\"\"\n        if key in self._services:\n            return True\n        return False\n\n    def set(self, key: str, value: object) -> None:\n        \"\"\"\n        Caches a value for the lifetime of the current turn.\n        :param key:\n        :param value:\n        :return:\n        \"\"\"\n        if not key or not isinstance(key, str):\n            raise KeyError('\"key\" must be a valid string.')\n\n        self._services[key] = value\n\n    async def send_activity(\n        self, *activity_or_text: Union[Activity, str]\n    ) -> ResourceResponse:\n        \"\"\"\n        Sends a single activity or message to the user.\n        :param activity_or_text:\n        :return:\n        \"\"\"\n        reference = TurnContext.get_conversation_reference(self.activity)\n\n        output = [\n            TurnContext.apply_conversation_reference(\n                Activity(text=a, type=\"message\") if isinstance(a, str) else a, reference\n            )\n            for a in activity_or_text\n        ]\n        for activity in output:\n            if not activity.input_hint:\n                activity.input_hint = \"acceptingInput\"\n\n        async def callback(context: \"TurnContext\", output):\n            responses = await context.adapter.send_activities(context, output)\n            context._responded = True  # pylint: disable=protected-access\n            return responses\n\n        result = await self._emit(\n            self._on_send_activities, output, callback(self, output)\n        )\n\n        return result[0] if result else ResourceResponse()\n\n    async def update_activity(self, activity: Activity):\n        \"\"\"\n        Replaces an existing activity.\n        :param activity:\n        :return:\n        \"\"\"\n        return await self._emit(\n            self._on_update_activity,\n            activity,\n            self.adapter.update_activity(self, activity),\n        )\n\n    async def delete_activity(self, id_or_reference: Union[str, ConversationReference]):\n        \"\"\"\n        Deletes an existing activity.\n        :param id_or_reference:\n        :return:\n        \"\"\"\n        if isinstance(id_or_reference, str):\n            reference = TurnContext.get_conversation_reference(self.activity)\n            reference.activity_id = id_or_reference\n        else:\n            reference = id_or_reference\n        return await self._emit(\n            self._on_delete_activity,\n            reference,\n            self.adapter.delete_activity(self, reference),\n        )\n\n    def on_send_activities(self, handler) -> \"TurnContext\":\n        \"\"\"\n        Registers a handler to be notified of and potentially intercept the sending of activities.\n        :param handler:\n        :return:\n        \"\"\"\n        self._on_send_activities.append(handler)\n        return self\n\n    def on_update_activity(self, handler) -> \"TurnContext\":\n        \"\"\"\n        Registers a handler to be notified of and potentially intercept an activity being updated.\n        :param handler:\n        :return:\n        \"\"\"\n        self._on_update_activity.append(handler)\n        return self\n\n    def on_delete_activity(self, handler) -> \"TurnContext\":\n        \"\"\"\n        Registers a handler to be notified of and potentially intercept an activity being deleted.\n        :param handler:\n        :return:\n        \"\"\"\n        self._on_delete_activity.append(handler)\n        return self\n\n    async def _emit(self, plugins, arg, logic):\n        handlers = copy(plugins)\n\n        async def emit_next(i: int):\n            context = self\n            try:\n                if i < len(handlers):\n\n                    async def next_handler():\n                        await emit_next(i + 1)\n\n                    await handlers[i](context, arg, next_handler)\n\n            except Exception as error:\n                raise error\n\n        await emit_next(0)\n        # This should be changed to `return await logic()`\n        return await logic\n\n    @staticmethod\n    def get_conversation_reference(activity: Activity) -> ConversationReference:\n        \"\"\"\n        Returns the conversation reference for an activity. This can be saved as a plain old JSON\n        object and then later used to message the user proactively.\n\n        Usage Example:\n        reference = TurnContext.get_conversation_reference(context.request)\n        :param activity:\n        :return:\n        \"\"\"\n        return ConversationReference(\n            activity_id=activity.id,\n            user=copy(activity.from_property),\n            bot=copy(activity.recipient),\n            conversation=copy(activity.conversation),\n            channel_id=activity.channel_id,\n            service_url=activity.service_url,\n        )\n\n    @staticmethod\n    def apply_conversation_reference(\n        activity: Activity, reference: ConversationReference, is_incoming: bool = False\n    ) -> Activity:\n        \"\"\"\n        Updates an activity with the delivery information from a conversation reference. Calling\n        this after get_conversation_reference on an incoming activity\n        will properly address the reply to a received activity.\n        :param activity:\n        :param reference:\n        :param is_incoming:\n        :return:\n        \"\"\"\n        activity.channel_id = reference.channel_id\n        activity.service_url = reference.service_url\n        activity.conversation = reference.conversation\n        if is_incoming:\n            activity.from_property = reference.user\n            activity.recipient = reference.bot\n            if reference.activity_id:\n                activity.id = reference.activity_id\n        else:\n            activity.from_property = reference.bot\n            activity.recipient = reference.user\n            if reference.activity_id:\n                activity.reply_to_id = reference.activity_id\n\n        return activity\n\n    @staticmethod\n    def get_reply_conversation_reference(\n        activity: Activity, reply: ResourceResponse\n    ) -> ConversationReference:\n        reference: ConversationReference = TurnContext.get_conversation_reference(\n            activity\n        )\n\n        # Update the reference with the new outgoing Activity's id.\n        reference.activity_id = reply.id\n\n        return reference\n\n    @staticmethod\n    def remove_recipient_mention(activity: Activity) -> str:\n        return TurnContext.remove_mention_text(activity, activity.recipient.id)\n\n    @staticmethod\n    def remove_mention_text(activity: Activity, identifier: str) -> str:\n        mentions = TurnContext.get_mentions(activity)\n        for mention in mentions:\n            if mention.mentioned.id == identifier:\n                mention_name_match = re.match(\n                    r\"<at(.*)>(.*?)<\\/at>\", mention.text, re.IGNORECASE\n                )\n                if mention_name_match:\n                    activity.text = re.sub(\n                        mention_name_match.groups()[1], \"\", activity.text\n                    )\n                    activity.text = re.sub(r\"<at><\\/at>\", \"\", activity.text)\n        return activity.text\n\n    @staticmethod\n    def get_mentions(activity: Activity) -> List[Mention]:\n        result: List[Mention] = []\n        if activity.entities is not None:\n            for entity in activity.entities:\n                if entity.type.lower() == \"mention\":\n                    result.append(entity)\n        return result\n", "path": "libraries/botbuilder-core/botbuilder/core/turn_context.py"}]}