Repository: facebookresearch/ParlAI

Issue:
MTurk Agent cannot observe distinct messages
Hi @JackUrb, I have modified the mturk model evaluator task example according to my need. I wanted to show multiple messages after each round of dialog. 

## The Problem

When I try to show two messages on the chat interface one after other, then only second message is being shown twice. For example:

```
msg1 = "Message 1"
msg2 = "Message 2"
```
Ideally it should print `Message 1` and then `Message 2` on the interface but that doesn't seem to happen. It only prints `Message 2` both the times. Please see the modified code of model evaluator task here: https://github.com/deshraj/ParlAI/blob/eval/parlai/mturk/tasks/model_evaluator/worlds.py#L35

Here is the screenshot of the error: 

![screen shot 2018-01-26 at 4 03 03 pm](https://user-images.githubusercontent.com/2945708/35460548-6d6c14aa-02b2-11e8-87fd-3dd575b522e6.png)

Terminal log: https://pastebin.com/ci2ZHX7t

Let me know if I am missing something here.


Discussion:
Hi @deshraj: The issue here is that you're reusing the action dictionary for both actions. Admittedly this is a little unclear, but in order to process the send events through a socket, these messages are put into a queue that is handled by a worker thread rather than immediately at the moment observe is called. If you alter the data packet before the socket worker thread is able to push it through, the receiving agent will get the same message twice rather than the two messages you intended. To resolve this you should use a fresh dict or perform a dict copy and alter the copied dict.
@JackUrb: Yeah, what you just suggested worked for me but I am curious to know why it's not working. I tried to debug but couldn't find anything. 

Also, one more interesting thing I noticed: if you use the same dict for sending messages, then when you refresh the page, then the message is shown only once instead of showing the two duplicate messages. I am trying to see if I can debug it. Please let me know if you can find a fix. 
The only 'fix' per-se would be to duplicate the dict before it is encapsulated into a Packet here:
https://github.com/facebookresearch/ParlAI/blob/c0ca783195559688aa19063162fe2977734c2882/parlai/mturk/core/mturk_manager.py#L905

There is no fix without duplicating the dict, as to make the sockets work seamlessly all actions surrounding them have to be nonblocking and occur in separate threads. When you reuse a dict then the observe calls are actually queueing up observations of the same dict, so changes will be seen through both messages. 

As far as frontend de-duping goes, this is caused by the way that the 'refresh data-restoration packet' is kept track of. This line is appending the used action dict directly rather than a packet to the messages queue:
https://github.com/facebookresearch/ParlAI/blob/c0ca783195559688aa19063162fe2977734c2882/parlai/mturk/core/mturk_manager.py#L925
This array is later sent to the frontend in a `RESTORE_STATE` command:
https://github.com/facebookresearch/ParlAI/blob/c0ca783195559688aa19063162fe2977734c2882/parlai/mturk/core/mturk_manager.py#L289
That command is received on the frontend, and the messages are processed and deduped by message id here:
https://github.com/facebookresearch/ParlAI/blob/c0ca783195559688aa19063162fe2977734c2882/parlai/mturk/core/server/html/core.html#L647
But where is the `'message_id'` in the action dictionary being set in the first place? That happens the first time you call observe on an action, when the observe call calls `send_message` on that action for the first time:
https://github.com/facebookresearch/ParlAI/blob/c0ca783195559688aa19063162fe2977734c2882/parlai/mturk/core/mturk_manager.py#L903
Thus by reusing a packet, the message isn't being seen as unique, so it is getting thrown out on a refresh.

There's definitely a use case to being able to maintain a message_id from a message, which currently can only be achieved by setting it yourself on an action or by checking the field on an observed action. To maintain that, I'd be happy to accept a PR that duplicates the data dict in the first line of `send_message` via `data = data.copy()` (with a comment describing why, namely the fact that it prevents data from being changed after an observed call), and then having the `send_message` function return the `message_id` used for that message send.
I do feel such a PR would be an improvement to the consistency of the MTurk features

Resolving patch:
diff --git a/parlai/mturk/core/mturk_manager.py b/parlai/mturk/core/mturk_manager.py
--- a/parlai/mturk/core/mturk_manager.py
+++ b/parlai/mturk/core/mturk_manager.py
@@ -897,6 +897,7 @@ def send_message(self, receiver_id, assignment_id, data,
         """Send a message through the socket manager,
         update conversation state
         """
+        data = data.copy()  # Ensure data packet is sent in current state
         data['type'] = data_model.MESSAGE_TYPE_MESSAGE
         # Force messages to have a unique ID
         if 'message_id' not in data:
@@ -924,6 +925,7 @@ def send_message(self, receiver_id, assignment_id, data,
         if agent is not None:
             agent.state.messages.append(packet.data)
         self.socket_manager.queue_packet(packet)
+        return data['message_id']
 
     def send_command(self, receiver_id, assignment_id, data, blocking=True,
                      ack_func=None):


Test patch: