ChatMessage & Entity

On this page

Overview

Two small dataclasses. Entity is actively used by ConversationEntityMemory. ChatMessage is exported from both memory.core and the top-level memory package but — after inspecting every module in this source tree — is never constructed or referenced by any other class in the package. The four built-in ConversationXMemory classes all store turns as plain dicts ({"input": ..., "output": ...}), not ChatMessage instances.

ChatMessage

Python · 9 lines
@dataclass
class ChatMessage:
    input: str
    output: str
    timestamp: float = field(default_factory=time.time)
    metadata: Dict[str, Any] = field(default_factory=dict)

    def to_dict(self) -> Dict[str, Any]: ...
    def to_text(self) -> str: ...
MethodReturns
to_dict(){'input', 'output', 'timestamp', 'metadata'}
to_text()f"user: {self.input}\n assistant: {self.output}" (note the leading space before "assistant:", which differs from the "user: {x}\nassistant: {y}" format — no leading space — used elsewhere in the package, e.g. ConversationBufferMemory._format_messages_as_text)

[!NOTE] Vestigial class Since nothing in this source tree instantiates ChatMessage, treat it as available for your own external use (e.g. if you want a typed alternative to the plain dicts the built-in memories use internally) rather than as part of any documented internal data flow.

Entity

Python · 10 lines
@dataclass
class Entity:
    name: str
    entity_type: str
    contexts: List[str] = field(default_factory=list)
    first_seen: float = field(default_factory=time.time)
    last_seen: float = field(default_factory=time.time)

    def add_context(self, context: str): ...
    def get_recent_contexts(self, limit: int = 3) -> List[str]: ...
ParameterTypeRequiredDefaultNotes
namestrYes—The entity's extracted name/label.
entity_typestrYes—Free-form (e.g. "person", "place") — ConversationEntityMemory always passes the literal string "unknown" and never updates it.
contextsList[str]No[]Accumulated raw text snippets mentioning this entity.
first_seenfloatNotime.time() at constructionNot updated after construction.
last_seenfloatNotime.time() at constructionUpdated by add_context().

add_context(context: str) -> None

Appends context to self.contexts (unconditionally — no deduplication, no length cap) and updates last_seen = time.time(). Because there's no cap, an entity mentioned across a very long-running conversation will accumulate an unbounded contexts list.

get_recent_contexts(limit: int = 3) -> List[str]

Python
return self.contexts[-limit:]

Returns the most recent limit contexts. Same slicing edge case as elsewhere in this package: get_recent_contexts(0) returns all contexts (contexts[-0:] equals contexts[0:] in Python), not zero — see Known Issues.

Thread safety

Neither dataclass performs locking; both are simple in-memory records mutated directly by their owning ConversationEntityMemory instance.

Examples

Python · 13 lines
from zerda.memory import ChatMessage, Entity
import time

# ChatMessage — available for external use, not used internally by this package
msg = ChatMessage(input="Hi", output="Hello!")
print(msg.to_text())

# Entity — as used internally by ConversationEntityMemory
e = Entity(name="Sarah", entity_type="unknown")
e.add_context("Sarah mentioned she works at Acme Corp.")
e.add_context("Sarah's favorite color is teal.")
print(e.get_recent_contexts(limit=1))  # ["Sarah's favorite color is teal."]
print(e.get_recent_contexts(limit=0))  # returns BOTH contexts, not none — see caveat above

Best practices

  • If you build your own conversation memory and want typed messages, ChatMessage is a reasonable starting point — but note it's disconnected from the rest of the package's data flow, so you'll need to convert to/from plain dicts if you interoperate with ContextBuilder or MemorySelector.
  • Avoid calling get_recent_contexts(0) expecting an empty list.

Related pages