Skip to content

get_communication_history() renders raw dict instead of readable message text #193

@Harsh-617

Description

@Harsh-617

Describe the bug

get_communication_history() in EpisodicMemory, STLTMemory, and ShortTermMemory renders raw Python dictionaries instead of human-readable message strings when passed to the LLM prompt.

This happens because the speak_to tool stores message content as a nested dict:

# speak_to stores:
recipient.memory.add_to_memory(
    type="message",
    content={"message": "meet me at the north", "sender": 7, "recipients": [1, 2]},
)

Which results in entry.content["message"] being a dict, not a string. But all three get_communication_history() implementations format it directly into the f-string:

f"step {entry.step}: {entry.content['message']}\n\n"
# Actual output:
# step 5: {'message': 'meet me at the north', 'sender': 7, 'recipients': [1, 2]}

This garbled output is then injected into the ReAct reasoning prompt, degrading the LLM's ability to understand inter-agent communication.

Expected behavior

get_communication_history() should return a clean, readable string per message entry:

step 5: Agent 7 says: meet me at the north

To Reproduce

from unittest.mock import Mock
from mesa_llm.memory.st_memory import ShortTermMemory
from mesa_llm.memory.memory import MemoryEntry

agent = Mock()
agent.model.steps = 1
memory = ShortTermMemory(agent=agent, display=False)

# This is the structure speak_to produces
entry = MemoryEntry(
    content={"message": {"message": "meet me at the north", "sender": 7, "recipients": [1]}},
    step=5,
    agent=agent,
)
memory.short_term_memory.append(entry)
print(memory.get_communication_history())
# Current output:  step 5: {'message': 'meet me at the north', 'sender': 7, 'recipients': [1]}
# Expected output: step 5: Agent 7 says: meet me at the north

The same issue reproduces with STLTMemory and EpisodicMemory.

Additional context

  • Affects all three memory implementations: ShortTermMemory, STLTMemory, EpisodicMemory
  • The EpisodicMemory case is slightly different — _finalize_entry additionally wraps the content under the event-type key and appends an "importance" score, so entry.content["message"] becomes {"message": "...", "sender": 7, "importance": 3} — still a dict
  • The bug silently corrupts the communication context window fed to the LLM on every reasoning step where agents have exchanged messages
  • The existing test_get_communication_history test missed it because it constructed entries with a plain string "message": "Hello" rather than the nested dict structure speak_to actually produces

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions