diff --git a/changelog/5361.bugfix.rst b/changelog/5361.bugfix.rst new file mode 100644 index 000000000000..ac5cf20cc4a5 --- /dev/null +++ b/changelog/5361.bugfix.rst @@ -0,0 +1 @@ +Fixed bug where starting or ending a response with ``\n\n`` led to one of the responses returned being empty. diff --git a/docs/conf.py b/docs/conf.py index 7c6816575d5e..10d8e393d191 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -139,7 +139,7 @@ "fixed_sidebar": True, "product": "Rasa", "base_url": "https://rasa.com/docs/rasa/", - "canonical_url": "https://rasa.com/docs/rasa/" + "canonical_url": "https://rasa.com/docs/rasa/", } # html_theme_options = {} diff --git a/rasa/core/channels/botframework.py b/rasa/core/channels/botframework.py index ad60f490563f..590497bfa40a 100644 --- a/rasa/core/channels/botframework.py +++ b/rasa/core/channels/botframework.py @@ -109,7 +109,7 @@ async def send(self, message_data: Dict[Text, Any]) -> None: async def send_text_message( self, recipient_id: Text, text: Text, **kwargs: Any ) -> None: - for message_part in text.split("\n\n"): + for message_part in text.strip().split("\n\n"): text_message = {"text": message_part} message = self.prepare_message(recipient_id, text_message) await self.send(message) diff --git a/rasa/core/channels/channel.py b/rasa/core/channels/channel.py index 277b35fcdbad..5c362af75e95 100644 --- a/rasa/core/channels/channel.py +++ b/rasa/core/channels/channel.py @@ -324,7 +324,7 @@ async def _persist_message(self, message: Dict[Text, Any]) -> None: async def send_text_message( self, recipient_id: Text, text: Text, **kwargs: Any ) -> None: - for message_part in text.split("\n\n"): + for message_part in text.strip().split("\n\n"): await self._persist_message(self._message(recipient_id, text=message_part)) async def send_image_url( diff --git a/rasa/core/channels/facebook.py b/rasa/core/channels/facebook.py index fb5afb1ab6c3..b3df1f8b5ec2 100644 --- a/rasa/core/channels/facebook.py +++ b/rasa/core/channels/facebook.py @@ -148,7 +148,7 @@ async def send_text_message( ) -> None: """Send a message through this channel.""" - for message_part in text.split("\n\n"): + for message_part in text.strip().split("\n\n"): self.send(recipient_id, FBText(text=message_part)) async def send_image_url( diff --git a/rasa/core/channels/mattermost.py b/rasa/core/channels/mattermost.py index df4d9de0b329..9208d03aed59 100644 --- a/rasa/core/channels/mattermost.py +++ b/rasa/core/channels/mattermost.py @@ -65,7 +65,7 @@ def _post_data_to_channel(self, data) -> Response: async def send_text_message( self, recipient_id: Text, text: Text, **kwargs: Any ) -> None: - for message_part in text.split("\n\n"): + for message_part in text.strip().split("\n\n"): self._post_message_to_channel(self.bot_channel, message_part) async def send_custom_json( diff --git a/rasa/core/channels/rocketchat.py b/rasa/core/channels/rocketchat.py index 88e1caa2a7a6..2cc221012f94 100644 --- a/rasa/core/channels/rocketchat.py +++ b/rasa/core/channels/rocketchat.py @@ -36,7 +36,7 @@ async def send_text_message( ) -> None: """Send message to output channel""" - for message_part in text.split("\n\n"): + for message_part in text.strip().split("\n\n"): self.rocket.chat_post_message(message_part, room_id=recipient_id) async def send_image_url( diff --git a/rasa/core/channels/slack.py b/rasa/core/channels/slack.py index 35060b6e60f7..51dfb966286d 100644 --- a/rasa/core/channels/slack.py +++ b/rasa/core/channels/slack.py @@ -34,7 +34,7 @@ async def send_text_message( self, recipient_id: Text, text: Text, **kwargs: Any ) -> None: recipient = self.slack_channel or recipient_id - for message_part in text.split("\n\n"): + for message_part in text.strip().split("\n\n"): await self.client.chat_postMessage( channel=recipient, as_user=True, text=message_part, type="mrkdwn", ) diff --git a/rasa/core/channels/socketio.py b/rasa/core/channels/socketio.py index 71e97665e5db..30668dac32fc 100644 --- a/rasa/core/channels/socketio.py +++ b/rasa/core/channels/socketio.py @@ -43,7 +43,7 @@ async def send_text_message( ) -> None: """Send a message through this channel.""" - for message_part in text.split("\n\n"): + for message_part in text.strip().split("\n\n"): await self._send_message(self.sid, {"text": message_part}) async def send_image_url( @@ -66,7 +66,7 @@ async def send_text_with_buttons( # split text and create a message for each text fragment # the `or` makes sure there is at least one message we can attach the quick # replies to - message_parts = text.split("\n\n") or [text] + message_parts = text.strip().split("\n\n") or [text] messages = [{"text": message, "quick_replies": []} for message in message_parts] # attach all buttons to the last text fragment diff --git a/rasa/core/channels/telegram.py b/rasa/core/channels/telegram.py index 68ad51f0186d..605d304b92b5 100644 --- a/rasa/core/channels/telegram.py +++ b/rasa/core/channels/telegram.py @@ -32,7 +32,7 @@ def __init__(self, access_token: Optional[Text]) -> None: async def send_text_message( self, recipient_id: Text, text: Text, **kwargs: Any ) -> None: - for message_part in text.split("\n\n"): + for message_part in text.strip().split("\n\n"): self.send_message(recipient_id, message_part) async def send_image_url( diff --git a/rasa/core/channels/twilio.py b/rasa/core/channels/twilio.py index 292d898dde60..1f1715c4a71d 100644 --- a/rasa/core/channels/twilio.py +++ b/rasa/core/channels/twilio.py @@ -52,7 +52,7 @@ async def send_text_message( """Sends text message""" message_data = {"to": recipient_id, "from_": self.twilio_number} - for message_part in text.split("\n\n"): + for message_part in text.strip().split("\n\n"): message_data.update({"body": message_part}) await self._send_message(message_data) diff --git a/rasa/core/channels/webexteams.py b/rasa/core/channels/webexteams.py index 8da789a41981..50bbe41e3aa5 100644 --- a/rasa/core/channels/webexteams.py +++ b/rasa/core/channels/webexteams.py @@ -27,7 +27,7 @@ async def send_text_message( self, recipient_id: Text, text: Text, **kwargs: Any ) -> None: recipient = self.room or recipient_id - for message_part in text.split("\n\n"): + for message_part in text.strip().split("\n\n"): self.api.messages.create(roomId=recipient, text=message_part) async def send_image_url( diff --git a/tests/core/test_channels.py b/tests/core/test_channels.py index 7163a2f11e43..35d331bc1606 100644 --- a/tests/core/test_channels.py +++ b/tests/core/test_channels.py @@ -57,6 +57,9 @@ def fake_send_message(*args, **kwargs): async def test_send_response(default_channel, default_tracker): text_only_message = {"text": "hey"} + multiline_text_message = { + "text": "This message should come first: \n\nThis is message two \nThis as well\n\n" + } image_only_message = {"image": "https://i.imgur.com/nGF1K8f.jpg"} text_and_image_message = { "text": "look at this", @@ -68,6 +71,9 @@ async def test_send_response(default_channel, default_tracker): } await default_channel.send_response(default_tracker.sender_id, text_only_message) + await default_channel.send_response( + default_tracker.sender_id, multiline_text_message + ) await default_channel.send_response(default_tracker.sender_id, image_only_message) await default_channel.send_response( default_tracker.sender_id, text_and_image_message @@ -75,25 +81,35 @@ async def test_send_response(default_channel, default_tracker): await default_channel.send_response(default_tracker.sender_id, custom_json_message) collected = default_channel.messages - assert len(collected) == 6 + assert len(collected) == 8 # text only message assert collected[0] == {"recipient_id": "my-sender", "text": "hey"} - # image only message + # multiline text message, should split on '\n\n' assert collected[1] == { "recipient_id": "my-sender", - "image": "https://i.imgur.com/nGF1K8f.jpg", + "text": "This message should come first: ", + } + assert collected[2] == { + "recipient_id": "my-sender", + "text": "This is message two \nThis as well", } - # text & image combined - will result in two messages - assert collected[2] == {"recipient_id": "my-sender", "text": "look at this"} + # image only message assert collected[3] == { "recipient_id": "my-sender", - "image": "https://i.imgur.com/T5xVo.jpg", + "image": "https://i.imgur.com/nGF1K8f.jpg", } + + # text & image combined - will result in two messages assert collected[4] == {"recipient_id": "my-sender", "text": "look at this"} assert collected[5] == { + "recipient_id": "my-sender", + "image": "https://i.imgur.com/T5xVo.jpg", + } + assert collected[6] == {"recipient_id": "my-sender", "text": "look at this"} + assert collected[7] == { "recipient_id": "my-sender", "custom": {"some_random_arg": "value", "another_arg": "value2"}, }