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()

```

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)

{"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"}]}