diff --git a/libraries/botbuilder-core/botbuilder/core/bot_framework_adapter.py b/libraries/botbuilder-core/botbuilder/core/bot_framework_adapter.py index ffe81ec7d..1a4407895 100644 --- a/libraries/botbuilder-core/botbuilder/core/bot_framework_adapter.py +++ b/libraries/botbuilder-core/botbuilder/core/bot_framework_adapter.py @@ -37,6 +37,7 @@ ConversationAccount, ConversationParameters, ConversationReference, + ExpectedReplies, TokenResponse, ResourceResponse, DeliveryModes, @@ -459,12 +460,12 @@ async def process_activity_with_identity( # Return the buffered activities in the response. In this case, the invoker # should deserialize accordingly: - # activities = [Activity().deserialize(activity) for activity in response.body] - if context.activity.delivery_mode == DeliveryModes.buffered_replies: - serialized_activities = [ - activity.serialize() for activity in context.buffered_replies - ] - return InvokeResponse(status=200, body=serialized_activities) + # activities = ExpectedReplies().deserialize(response.body).activities + if context.activity.delivery_mode == DeliveryModes.expect_replies: + expected_replies = ExpectedReplies( + activities=context.buffered_reply_activities + ).serialize() + return InvokeResponse(status=200, body=expected_replies) return None diff --git a/libraries/botbuilder-core/botbuilder/core/bot_framework_http_client.py b/libraries/botbuilder-core/botbuilder/core/bot_framework_http_client.py index 963cf8bd4..dc9dd1a9e 100644 --- a/libraries/botbuilder-core/botbuilder/core/bot_framework_http_client.py +++ b/libraries/botbuilder-core/botbuilder/core/bot_framework_http_client.py @@ -6,7 +6,7 @@ from logging import Logger import aiohttp -from botbuilder.schema import Activity +from botbuilder.schema import Activity, ExpectedReplies from botframework.connector.auth import ( ChannelProvider, CredentialProvider, @@ -110,14 +110,14 @@ async def post_buffered_activity( ) -> [Activity]: """ Helper method to return a list of activities when an Activity is being - sent with DeliveryMode == bufferedReplies. + sent with DeliveryMode == expectReplies. """ response = await self.post_activity( from_bot_id, to_bot_id, to_url, service_url, conversation_id, activity ) if not response or (response.status / 100) != 2: return [] - return [Activity().deserialize(activity) for activity in response.body] + return ExpectedReplies().deserialize(response.body).activities async def _get_app_credentials( self, app_id: str, oauth_scope: str diff --git a/libraries/botbuilder-core/botbuilder/core/turn_context.py b/libraries/botbuilder-core/botbuilder/core/turn_context.py index b3ec326c8..00bdf5d43 100644 --- a/libraries/botbuilder-core/botbuilder/core/turn_context.py +++ b/libraries/botbuilder-core/botbuilder/core/turn_context.py @@ -51,8 +51,8 @@ def __init__(self, adapter_or_context, request: Activity = None): self._turn_state = {} - # A list of activities to send when `context.Activity.DeliveryMode == 'bufferedReplies'` - self.buffered_replies = [] + # A list of activities to send when `context.Activity.DeliveryMode == 'expectReplies'` + self.buffered_reply_activities = [] @property def turn_state(self) -> Dict[str, object]: @@ -198,10 +198,10 @@ def activity_validator(activity: Activity) -> Activity: async def logic(): nonlocal sent_non_trace_activity - if self.activity.delivery_mode == DeliveryModes.buffered_replies: + if self.activity.delivery_mode == DeliveryModes.expect_replies: responses = [] for activity in output: - self.buffered_replies.append(activity) + self.buffered_reply_activities.append(activity) responses.append(ResourceResponse()) if sent_non_trace_activity: diff --git a/libraries/botbuilder-core/tests/test_bot_framework_adapter.py b/libraries/botbuilder-core/tests/test_bot_framework_adapter.py index 871e616a1..891ecdeb5 100644 --- a/libraries/botbuilder-core/tests/test_bot_framework_adapter.py +++ b/libraries/botbuilder-core/tests/test_bot_framework_adapter.py @@ -20,6 +20,7 @@ ConversationResourceResponse, ChannelAccount, DeliveryModes, + ExpectedReplies, ) from botframework.connector.aio import ConnectorClient from botframework.connector.auth import ( @@ -578,7 +579,7 @@ async def callback(context: TurnContext): refs, callback, claims_identity=skills_identity, audience=skill_2_app_id ) - async def test_delivery_mode_buffered_replies(self): + async def test_delivery_mode_expect_replies(self): mock_credential_provider = unittest.mock.create_autospec(CredentialProvider) settings = BotFrameworkAdapterSettings( @@ -595,7 +596,7 @@ async def callback(context: TurnContext): type=ActivityTypes.message, channel_id="emulator", service_url="http://tempuri.org/whatever", - delivery_mode=DeliveryModes.buffered_replies, + delivery_mode=DeliveryModes.expect_replies, text="hello world", ) @@ -613,11 +614,11 @@ async def callback(context: TurnContext): ) assert invoke_response assert invoke_response.status == 200 - activities = invoke_response.body + activities = ExpectedReplies().deserialize(invoke_response.body).activities assert len(activities) == 3 - assert activities[0]["text"] == "activity 1" - assert activities[1]["text"] == "activity 2" - assert activities[2]["text"] == "activity 3" + assert activities[0].text == "activity 1" + assert activities[1].text == "activity 2" + assert activities[2].text == "activity 3" assert ( adapter.connector_client_mock.conversations.send_to_conversation.call_count == 0 diff --git a/libraries/botbuilder-schema/botbuilder/schema/__init__.py b/libraries/botbuilder-schema/botbuilder/schema/__init__.py index bb3e7d75f..5fcb88ed7 100644 --- a/libraries/botbuilder-schema/botbuilder/schema/__init__.py +++ b/libraries/botbuilder-schema/botbuilder/schema/__init__.py @@ -27,6 +27,7 @@ from ._models_py3 import ConversationReference from ._models_py3 import ConversationResourceResponse from ._models_py3 import ConversationsResult + from ._models_py3 import ExpectedReplies from ._models_py3 import Entity from ._models_py3 import Error from ._models_py3 import ErrorResponse, ErrorResponseException @@ -74,6 +75,7 @@ from ._models import ConversationReference from ._models import ConversationResourceResponse from ._models import ConversationsResult + from ._models import ExpectedReplies from ._models import Entity from ._models import Error from ._models import ErrorResponse, ErrorResponseException @@ -136,6 +138,7 @@ "ConversationReference", "ConversationResourceResponse", "ConversationsResult", + "ExpectedReplies", "Entity", "Error", "ErrorResponse", diff --git a/libraries/botbuilder-schema/botbuilder/schema/_connector_client_enums.py b/libraries/botbuilder-schema/botbuilder/schema/_connector_client_enums.py index 68aab5ecf..ba33d9c00 100644 --- a/libraries/botbuilder-schema/botbuilder/schema/_connector_client_enums.py +++ b/libraries/botbuilder-schema/botbuilder/schema/_connector_client_enums.py @@ -99,7 +99,7 @@ class DeliveryModes(str, Enum): normal = "normal" notification = "notification" - buffered_replies = "bufferedReplies" + expect_replies = "expectReplies" class ContactRelationUpdateActionTypes(str, Enum): diff --git a/libraries/botbuilder-schema/botbuilder/schema/_models.py b/libraries/botbuilder-schema/botbuilder/schema/_models.py index 2cb85d663..31e1a3f31 100644 --- a/libraries/botbuilder-schema/botbuilder/schema/_models.py +++ b/libraries/botbuilder-schema/botbuilder/schema/_models.py @@ -133,7 +133,7 @@ class Activity(Model): :param delivery_mode: A delivery hint to signal to the recipient alternate delivery paths for the activity. The default delivery mode is "default". Possible values include: 'normal', - 'notification' + 'notification', 'expectReplies' :type delivery_mode: str or ~botframework.connector.models.DeliveryModes :param listen_for: List of phrases and references that speech and language priming systems should listen for @@ -806,6 +806,21 @@ def __init__(self, **kwargs): self.conversations = kwargs.get("conversations", None) +class ExpectedReplies(Model): + """ExpectedReplies. + + :param activities: A collection of Activities that conforms to the + ExpectedReplies schema. + :type activities: list[~botframework.connector.models.Activity] + """ + + _attribute_map = {"activities": {"key": "activities", "type": "[Activity]"}} + + def __init__(self, **kwargs): + super(ExpectedReplies, self).__init__(**kwargs) + self.activities = kwargs.get("activities", None) + + class Entity(Model): """Metadata object pertaining to an activity. diff --git a/libraries/botbuilder-schema/botbuilder/schema/_models_py3.py b/libraries/botbuilder-schema/botbuilder/schema/_models_py3.py index fe583a9b8..792ab6c13 100644 --- a/libraries/botbuilder-schema/botbuilder/schema/_models_py3.py +++ b/libraries/botbuilder-schema/botbuilder/schema/_models_py3.py @@ -133,7 +133,7 @@ class Activity(Model): :param delivery_mode: A delivery hint to signal to the recipient alternate delivery paths for the activity. The default delivery mode is "default". Possible values include: 'normal', - 'notification' + 'notification', 'expectReplies' :type delivery_mode: str or ~botframework.connector.models.DeliveryModes :param listen_for: List of phrases and references that speech and language priming systems should listen for @@ -978,6 +978,21 @@ def __init__( self.conversations = conversations +class ExpectedReplies(Model): + """ExpectedReplies. + + :param activities: A collection of Activities that conforms to the + ExpectedReplies schema. + :type activities: list[~botframework.connector.models.Activity] + """ + + _attribute_map = {"activities": {"key": "activities", "type": "[Activity]"}} + + def __init__(self, *, activities=None, **kwargs) -> None: + super(ExpectedReplies, self).__init__(**kwargs) + self.activities = activities + + class Entity(Model): """Metadata object pertaining to an activity. diff --git a/libraries/swagger/ConnectorAPI.json b/libraries/swagger/ConnectorAPI.json index f3a5b6e49..bae96e716 100644 --- a/libraries/swagger/ConnectorAPI.json +++ b/libraries/swagger/ConnectorAPI.json @@ -2293,7 +2293,8 @@ "description": "Values for deliveryMode field", "enum": [ "normal", - "notification" + "notification", + "expectReplies" ], "type": "string", "properties": {}, diff --git a/samples/experimental/skills-buffered/parent/bots/parent_bot.py b/samples/experimental/skills-buffered/parent/bots/parent_bot.py index 91b85b654..1aa077624 100644 --- a/samples/experimental/skills-buffered/parent/bots/parent_bot.py +++ b/samples/experimental/skills-buffered/parent/bots/parent_bot.py @@ -26,7 +26,7 @@ async def on_message_activity(self, turn_context: TurnContext): TurnContext.apply_conversation_reference( activity, TurnContext.get_conversation_reference(turn_context.activity) ) - activity.delivery_mode = DeliveryModes.buffered_replies + activity.delivery_mode = DeliveryModes.expect_replies activities = await self.client.post_buffered_activity( None,