prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  [PORT] Add EndOfConversationCodes to EndOfConversation activity from Skill
  > Port this change from botbuilder-dotnet/master branch:
  https://github.com/microsoft/botbuilder-dotnet/pull/4235
  
  Fixes https://github.com/microsoft/botframework-sdk/issues/5852
  
  
  # Changed projects
  * Microsoft.Bot.Builder.Dialogs
  * Microsoft.Bot.Builder.Dialogs.Tests
  
  
  
  
  
  --- 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-dialogs/botbuilder/dialogs/dialog_extensions.py`
  Content:
  ```
  1 # Copyright (c) Microsoft Corporation. All rights reserved.
  2 # Licensed under the MIT License.
  3 
  4 from botbuilder.core import BotAdapter, StatePropertyAccessor, TurnContext
  5 from botbuilder.core.skills import SkillHandler, SkillConversationReference
  6 
  7 from botbuilder.dialogs import (
  8     Dialog,
  9     DialogEvents,
  10     DialogSet,
  11     DialogTurnStatus,
  12 )
  13 from botbuilder.schema import Activity, ActivityTypes
  14 from botframework.connector.auth import (
  15     ClaimsIdentity,
  16     SkillValidation,
  17     AuthenticationConstants,
  18     GovernmentConstants,
  19 )
  20 
  21 
  22 class DialogExtensions:
  23     @staticmethod
  24     async def run_dialog(
  25         dialog: Dialog, turn_context: TurnContext, accessor: StatePropertyAccessor
  26     ):
  27         """
  28         Creates a dialog stack and starts a dialog, pushing it onto the stack.
  29         """
  30 
  31         dialog_set = DialogSet(accessor)
  32         dialog_set.add(dialog)
  33 
  34         dialog_context = await dialog_set.create_context(turn_context)
  35 
  36         # Handle EoC and Reprompt event from a parent bot (can be root bot to skill or skill to skill)
  37         if DialogExtensions.__is_from_parent_to_skill(turn_context):
  38             # Handle remote cancellation request from parent.
  39             if turn_context.activity.type == ActivityTypes.end_of_conversation:
  40                 if not dialog_context.stack:
  41                     # No dialogs to cancel, just return.
  42                     return
  43 
  44                 remote_cancel_text = "Skill was canceled through an EndOfConversation activity from the parent."
  45                 await turn_context.send_trace_activity(
  46                     f"Extension {Dialog.__name__}.run_dialog", label=remote_cancel_text,
  47                 )
  48 
  49                 # Send cancellation message to the dialog to ensure all the parents are canceled
  50                 # in the right order.
  51                 await dialog_context.cancel_all_dialogs()
  52                 return
  53 
  54             # Handle a reprompt event sent from the parent.
  55             if (
  56                 turn_context.activity.type == ActivityTypes.event
  57                 and turn_context.activity.name == DialogEvents.reprompt_dialog
  58             ):
  59                 if not dialog_context.stack:
  60                     # No dialogs to reprompt, just return.
  61                     return
  62 
  63                 await dialog_context.reprompt_dialog()
  64                 return
  65 
  66         # Continue or start the dialog.
  67         result = await dialog_context.continue_dialog()
  68         if result.status == DialogTurnStatus.Empty:
  69             result = await dialog_context.begin_dialog(dialog.id)
  70 
  71         # Skills should send EoC when the dialog completes.
  72         if (
  73             result.status == DialogTurnStatus.Complete
  74             or result.status == DialogTurnStatus.Cancelled
  75         ):
  76             if DialogExtensions.__send_eoc_to_parent(turn_context):
  77                 end_message_text = (
  78                     f"Dialog {dialog.id} has **completed**. Sending EndOfConversation."
  79                 )
  80                 await turn_context.send_trace_activity(
  81                     f"Extension {Dialog.__name__}.run_dialog",
  82                     label=end_message_text,
  83                     value=result.result,
  84                 )
  85 
  86                 activity = Activity(
  87                     type=ActivityTypes.end_of_conversation,
  88                     value=result.result,
  89                     locale=turn_context.activity.locale,
  90                 )
  91                 await turn_context.send_activity(activity)
  92 
  93     @staticmethod
  94     def __is_from_parent_to_skill(turn_context: TurnContext) -> bool:
  95         if turn_context.turn_state.get(SkillHandler.SKILL_CONVERSATION_REFERENCE_KEY):
  96             return False
  97 
  98         claims_identity = turn_context.turn_state.get(BotAdapter.BOT_IDENTITY_KEY)
  99         return isinstance(
  100             claims_identity, ClaimsIdentity
  101         ) and SkillValidation.is_skill_claim(claims_identity.claims)
  102 
  103     @staticmethod
  104     def __send_eoc_to_parent(turn_context: TurnContext) -> bool:
  105         claims_identity = turn_context.turn_state.get(BotAdapter.BOT_IDENTITY_KEY)
  106         if isinstance(
  107             claims_identity, ClaimsIdentity
  108         ) and SkillValidation.is_skill_claim(claims_identity.claims):
  109             # EoC Activities returned by skills are bounced back to the bot by SkillHandler.
  110             # In those cases we will have a SkillConversationReference instance in state.
  111             skill_conversation_reference: SkillConversationReference = turn_context.turn_state.get(
  112                 SkillHandler.SKILL_CONVERSATION_REFERENCE_KEY
  113             )
  114             if skill_conversation_reference:
  115                 # If the skillConversationReference.OAuthScope is for one of the supported channels,
  116                 # we are at the root and we should not send an EoC.
  117                 return (
  118                     skill_conversation_reference.oauth_scope
  119                     != AuthenticationConstants.TO_CHANNEL_FROM_BOT_OAUTH_SCOPE
  120                     and skill_conversation_reference.oauth_scope
  121                     != GovernmentConstants.TO_CHANNEL_FROM_BOT_OAUTH_SCOPE
  122                 )
  123             return True
  124 
  125         return False
  126
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/libraries/botbuilder-dialogs/botbuilder/dialogs/dialog_extensions.py b/libraries/botbuilder-dialogs/botbuilder/dialogs/dialog_extensions.py
  --- a/libraries/botbuilder-dialogs/botbuilder/dialogs/dialog_extensions.py
  +++ b/libraries/botbuilder-dialogs/botbuilder/dialogs/dialog_extensions.py
  @@ -1,22 +1,21 @@
   # Copyright (c) Microsoft Corporation. All rights reserved.
   # Licensed under the MIT License.
   
  +from botframework.connector.auth import (
  +    ClaimsIdentity,
  +    SkillValidation,
  +    AuthenticationConstants,
  +    GovernmentConstants,
  +)
   from botbuilder.core import BotAdapter, StatePropertyAccessor, TurnContext
   from botbuilder.core.skills import SkillHandler, SkillConversationReference
  -
   from botbuilder.dialogs import (
       Dialog,
       DialogEvents,
       DialogSet,
       DialogTurnStatus,
   )
  -from botbuilder.schema import Activity, ActivityTypes
  -from botframework.connector.auth import (
  -    ClaimsIdentity,
  -    SkillValidation,
  -    AuthenticationConstants,
  -    GovernmentConstants,
  -)
  +from botbuilder.schema import Activity, ActivityTypes, EndOfConversationCodes
   
   
   class DialogExtensions:
  @@ -87,6 +86,9 @@
                       type=ActivityTypes.end_of_conversation,
                       value=result.result,
                       locale=turn_context.activity.locale,
  +                    code=EndOfConversationCodes.completed_successfully
  +                    if result.status == DialogTurnStatus.Complete
  +                    else EndOfConversationCodes.user_cancelled,
                   )
                   await turn_context.send_activity(activity)
  
verification_info: {"golden_diff": "diff --git a/libraries/botbuilder-dialogs/botbuilder/dialogs/dialog_extensions.py b/libraries/botbuilder-dialogs/botbuilder/dialogs/dialog_extensions.py\n--- a/libraries/botbuilder-dialogs/botbuilder/dialogs/dialog_extensions.py\n+++ b/libraries/botbuilder-dialogs/botbuilder/dialogs/dialog_extensions.py\n@@ -1,22 +1,21 @@\n # Copyright (c) Microsoft Corporation. All rights reserved.\n # Licensed under the MIT License.\n \n+from botframework.connector.auth import (\n+    ClaimsIdentity,\n+    SkillValidation,\n+    AuthenticationConstants,\n+    GovernmentConstants,\n+)\n from botbuilder.core import BotAdapter, StatePropertyAccessor, TurnContext\n from botbuilder.core.skills import SkillHandler, SkillConversationReference\n-\n from botbuilder.dialogs import (\n     Dialog,\n     DialogEvents,\n     DialogSet,\n     DialogTurnStatus,\n )\n-from botbuilder.schema import Activity, ActivityTypes\n-from botframework.connector.auth import (\n-    ClaimsIdentity,\n-    SkillValidation,\n-    AuthenticationConstants,\n-    GovernmentConstants,\n-)\n+from botbuilder.schema import Activity, ActivityTypes, EndOfConversationCodes\n \n \n class DialogExtensions:\n@@ -87,6 +86,9 @@\n                     type=ActivityTypes.end_of_conversation,\n                     value=result.result,\n                     locale=turn_context.activity.locale,\n+                    code=EndOfConversationCodes.completed_successfully\n+                    if result.status == DialogTurnStatus.Complete\n+                    else EndOfConversationCodes.user_cancelled,\n                 )\n                 await turn_context.send_activity(activity)\n", "issue": "[PORT] Add EndOfConversationCodes to EndOfConversation activity from Skill\n> Port this change from botbuilder-dotnet/master branch:\nhttps://github.com/microsoft/botbuilder-dotnet/pull/4235\n\nFixes https://github.com/microsoft/botframework-sdk/issues/5852\n\n\r\n# Changed projects\r\n* Microsoft.Bot.Builder.Dialogs\r\n* Microsoft.Bot.Builder.Dialogs.Tests\r\n\r\n\r\n\n\n", "before_files": [{"content": "# Copyright (c) Microsoft Corporation. All rights reserved.\n# Licensed under the MIT License.\n\nfrom botbuilder.core import BotAdapter, StatePropertyAccessor, TurnContext\nfrom botbuilder.core.skills import SkillHandler, SkillConversationReference\n\nfrom botbuilder.dialogs import (\n    Dialog,\n    DialogEvents,\n    DialogSet,\n    DialogTurnStatus,\n)\nfrom botbuilder.schema import Activity, ActivityTypes\nfrom botframework.connector.auth import (\n    ClaimsIdentity,\n    SkillValidation,\n    AuthenticationConstants,\n    GovernmentConstants,\n)\n\n\nclass DialogExtensions:\n    @staticmethod\n    async def run_dialog(\n        dialog: Dialog, turn_context: TurnContext, accessor: StatePropertyAccessor\n    ):\n        \"\"\"\n        Creates a dialog stack and starts a dialog, pushing it onto the stack.\n        \"\"\"\n\n        dialog_set = DialogSet(accessor)\n        dialog_set.add(dialog)\n\n        dialog_context = await dialog_set.create_context(turn_context)\n\n        # Handle EoC and Reprompt event from a parent bot (can be root bot to skill or skill to skill)\n        if DialogExtensions.__is_from_parent_to_skill(turn_context):\n            # Handle remote cancellation request from parent.\n            if turn_context.activity.type == ActivityTypes.end_of_conversation:\n                if not dialog_context.stack:\n                    # No dialogs to cancel, just return.\n                    return\n\n                remote_cancel_text = \"Skill was canceled through an EndOfConversation activity from the parent.\"\n                await turn_context.send_trace_activity(\n                    f\"Extension {Dialog.__name__}.run_dialog\", label=remote_cancel_text,\n                )\n\n                # Send cancellation message to the dialog to ensure all the parents are canceled\n                # in the right order.\n                await dialog_context.cancel_all_dialogs()\n                return\n\n            # Handle a reprompt event sent from the parent.\n            if (\n                turn_context.activity.type == ActivityTypes.event\n                and turn_context.activity.name == DialogEvents.reprompt_dialog\n            ):\n                if not dialog_context.stack:\n                    # No dialogs to reprompt, just return.\n                    return\n\n                await dialog_context.reprompt_dialog()\n                return\n\n        # Continue or start the dialog.\n        result = await dialog_context.continue_dialog()\n        if result.status == DialogTurnStatus.Empty:\n            result = await dialog_context.begin_dialog(dialog.id)\n\n        # Skills should send EoC when the dialog completes.\n        if (\n            result.status == DialogTurnStatus.Complete\n            or result.status == DialogTurnStatus.Cancelled\n        ):\n            if DialogExtensions.__send_eoc_to_parent(turn_context):\n                end_message_text = (\n                    f\"Dialog {dialog.id} has **completed**. Sending EndOfConversation.\"\n                )\n                await turn_context.send_trace_activity(\n                    f\"Extension {Dialog.__name__}.run_dialog\",\n                    label=end_message_text,\n                    value=result.result,\n                )\n\n                activity = Activity(\n                    type=ActivityTypes.end_of_conversation,\n                    value=result.result,\n                    locale=turn_context.activity.locale,\n                )\n                await turn_context.send_activity(activity)\n\n    @staticmethod\n    def __is_from_parent_to_skill(turn_context: TurnContext) -> bool:\n        if turn_context.turn_state.get(SkillHandler.SKILL_CONVERSATION_REFERENCE_KEY):\n            return False\n\n        claims_identity = turn_context.turn_state.get(BotAdapter.BOT_IDENTITY_KEY)\n        return isinstance(\n            claims_identity, ClaimsIdentity\n        ) and SkillValidation.is_skill_claim(claims_identity.claims)\n\n    @staticmethod\n    def __send_eoc_to_parent(turn_context: TurnContext) -> bool:\n        claims_identity = turn_context.turn_state.get(BotAdapter.BOT_IDENTITY_KEY)\n        if isinstance(\n            claims_identity, ClaimsIdentity\n        ) and SkillValidation.is_skill_claim(claims_identity.claims):\n            # EoC Activities returned by skills are bounced back to the bot by SkillHandler.\n            # In those cases we will have a SkillConversationReference instance in state.\n            skill_conversation_reference: SkillConversationReference = turn_context.turn_state.get(\n                SkillHandler.SKILL_CONVERSATION_REFERENCE_KEY\n            )\n            if skill_conversation_reference:\n                # If the skillConversationReference.OAuthScope is for one of the supported channels,\n                # we are at the root and we should not send an EoC.\n                return (\n                    skill_conversation_reference.oauth_scope\n                    != AuthenticationConstants.TO_CHANNEL_FROM_BOT_OAUTH_SCOPE\n                    and skill_conversation_reference.oauth_scope\n                    != GovernmentConstants.TO_CHANNEL_FROM_BOT_OAUTH_SCOPE\n                )\n            return True\n\n        return False\n", "path": "libraries/botbuilder-dialogs/botbuilder/dialogs/dialog_extensions.py"}], "after_files": [{"content": "# Copyright (c) Microsoft Corporation. All rights reserved.\n# Licensed under the MIT License.\n\nfrom botframework.connector.auth import (\n    ClaimsIdentity,\n    SkillValidation,\n    AuthenticationConstants,\n    GovernmentConstants,\n)\nfrom botbuilder.core import BotAdapter, StatePropertyAccessor, TurnContext\nfrom botbuilder.core.skills import SkillHandler, SkillConversationReference\nfrom botbuilder.dialogs import (\n    Dialog,\n    DialogEvents,\n    DialogSet,\n    DialogTurnStatus,\n)\nfrom botbuilder.schema import Activity, ActivityTypes, EndOfConversationCodes\n\n\nclass DialogExtensions:\n    @staticmethod\n    async def run_dialog(\n        dialog: Dialog, turn_context: TurnContext, accessor: StatePropertyAccessor\n    ):\n        \"\"\"\n        Creates a dialog stack and starts a dialog, pushing it onto the stack.\n        \"\"\"\n\n        dialog_set = DialogSet(accessor)\n        dialog_set.add(dialog)\n\n        dialog_context = await dialog_set.create_context(turn_context)\n\n        # Handle EoC and Reprompt event from a parent bot (can be root bot to skill or skill to skill)\n        if DialogExtensions.__is_from_parent_to_skill(turn_context):\n            # Handle remote cancellation request from parent.\n            if turn_context.activity.type == ActivityTypes.end_of_conversation:\n                if not dialog_context.stack:\n                    # No dialogs to cancel, just return.\n                    return\n\n                remote_cancel_text = \"Skill was canceled through an EndOfConversation activity from the parent.\"\n                await turn_context.send_trace_activity(\n                    f\"Extension {Dialog.__name__}.run_dialog\", label=remote_cancel_text,\n                )\n\n                # Send cancellation message to the dialog to ensure all the parents are canceled\n                # in the right order.\n                await dialog_context.cancel_all_dialogs()\n                return\n\n            # Handle a reprompt event sent from the parent.\n            if (\n                turn_context.activity.type == ActivityTypes.event\n                and turn_context.activity.name == DialogEvents.reprompt_dialog\n            ):\n                if not dialog_context.stack:\n                    # No dialogs to reprompt, just return.\n                    return\n\n                await dialog_context.reprompt_dialog()\n                return\n\n        # Continue or start the dialog.\n        result = await dialog_context.continue_dialog()\n        if result.status == DialogTurnStatus.Empty:\n            result = await dialog_context.begin_dialog(dialog.id)\n\n        # Skills should send EoC when the dialog completes.\n        if (\n            result.status == DialogTurnStatus.Complete\n            or result.status == DialogTurnStatus.Cancelled\n        ):\n            if DialogExtensions.__send_eoc_to_parent(turn_context):\n                end_message_text = (\n                    f\"Dialog {dialog.id} has **completed**. Sending EndOfConversation.\"\n                )\n                await turn_context.send_trace_activity(\n                    f\"Extension {Dialog.__name__}.run_dialog\",\n                    label=end_message_text,\n                    value=result.result,\n                )\n\n                activity = Activity(\n                    type=ActivityTypes.end_of_conversation,\n                    value=result.result,\n                    locale=turn_context.activity.locale,\n                    code=EndOfConversationCodes.completed_successfully\n                    if result.status == DialogTurnStatus.Complete\n                    else EndOfConversationCodes.user_cancelled,\n                )\n                await turn_context.send_activity(activity)\n\n    @staticmethod\n    def __is_from_parent_to_skill(turn_context: TurnContext) -> bool:\n        if turn_context.turn_state.get(SkillHandler.SKILL_CONVERSATION_REFERENCE_KEY):\n            return False\n\n        claims_identity = turn_context.turn_state.get(BotAdapter.BOT_IDENTITY_KEY)\n        return isinstance(\n            claims_identity, ClaimsIdentity\n        ) and SkillValidation.is_skill_claim(claims_identity.claims)\n\n    @staticmethod\n    def __send_eoc_to_parent(turn_context: TurnContext) -> bool:\n        claims_identity = turn_context.turn_state.get(BotAdapter.BOT_IDENTITY_KEY)\n        if isinstance(\n            claims_identity, ClaimsIdentity\n        ) and SkillValidation.is_skill_claim(claims_identity.claims):\n            # EoC Activities returned by skills are bounced back to the bot by SkillHandler.\n            # In those cases we will have a SkillConversationReference instance in state.\n            skill_conversation_reference: SkillConversationReference = turn_context.turn_state.get(\n                SkillHandler.SKILL_CONVERSATION_REFERENCE_KEY\n            )\n            if skill_conversation_reference:\n                # If the skillConversationReference.OAuthScope is for one of the supported channels,\n                # we are at the root and we should not send an EoC.\n                return (\n                    skill_conversation_reference.oauth_scope\n                    != AuthenticationConstants.TO_CHANNEL_FROM_BOT_OAUTH_SCOPE\n                    and skill_conversation_reference.oauth_scope\n                    != GovernmentConstants.TO_CHANNEL_FROM_BOT_OAUTH_SCOPE\n                )\n            return True\n\n        return False\n", "path": "libraries/botbuilder-dialogs/botbuilder/dialogs/dialog_extensions.py"}]}