Skip to main content
EverOS supports group chat memory with multi-participant conversations. This guide shows how to build memory for team discussions, meeting notes, and collaborative contexts using the v1 SDK.

Prerequisites

Install the EverOS SDK:
pip install everos

Group Chat vs Assistant Scene

EverOS has two scene types with different memory extraction behaviors:
FeatureAssistant SceneGroup Chat Scene
Participants1 user + 1 assistantMultiple users
Episode MemoryIndividual perspectiveGroup + personal perspectives
Profile MemoryUser profilesAll participants’ profiles
Foresight MemorySupportedNot supported
EventLog MemorySupportedNot supported
In group chat scene, EverOS generates two types of episodes: group-level summaries (what the team discussed) and personal episodes (what each individual said/learned).

Setup: Register Group and Senders

First, register the group and each sender so EverOS knows about participants.
from everos import EverOS

client = EverOS()
groups = client.v1.groups
senders = client.v1.senders

# Create the group
groups.create(
    group_id="team_engineering",
    name="Engineering Team",
    description="Engineering team daily collaboration channel"
)

# Register each participant as a sender
senders.create(sender_id="user_alice", name="Alice")
senders.create(sender_id="user_bob", name="Bob")
senders.create(sender_id="user_carol", name="Carol")
senders.create(sender_id="bot_assistant", name="Team Bot")

Store Group Messages

Store messages from any participant in the group using client.v1.memories.group.add(). Each message must include sender_id and sender_name.
import time

group_mem = client.v1.memories.group
now_ms = int(time.time() * 1000)

# Store a batch of team discussion messages
resp = group_mem.add(
    group_id="team_engineering",
    messages=[
        {
            "role": "user",
            "sender_id": "user_alice",
            "sender_name": "Alice",
            "timestamp": now_ms,
            "content": "Team, we need to decide on the database for the new project.",
            "message_id": "msg_001",
        },
        {
            "role": "user",
            "sender_id": "user_bob",
            "sender_name": "Bob",
            "timestamp": now_ms + 5000,
            "content": "I think PostgreSQL would work well. It's what we know best.",
            "message_id": "msg_002",
        },
        {
            "role": "user",
            "sender_id": "user_carol",
            "sender_name": "Carol",
            "timestamp": now_ms + 10000,
            "content": "I agree with Bob. Plus we already have monitoring set up for Postgres.",
            "message_id": "msg_003",
        },
        {
            "role": "user",
            "sender_id": "user_alice",
            "sender_name": "Alice",
            "timestamp": now_ms + 15000,
            "content": "Good points. Let's go with PostgreSQL. Bob, can you set up the schema?",
            "message_id": "msg_004",
        },
        {
            "role": "user",
            "sender_id": "user_bob",
            "sender_name": "Bob",
            "timestamp": now_ms + 20000,
            "content": "Sure, I'll have a draft ready by Friday.",
            "message_id": "msg_005",
        },
    ],
)

Flush Group Memory

When a conversation topic reaches a natural boundary, flush to trigger memory extraction.
# Trigger memory extraction for the group
group_mem.flush(group_id="team_engineering")

Retrieve Group Memories

Search memories from a specific group.
memories = client.v1.memories

def search_group_memories(group_id: str, query: str):
    """Search memories within a group."""
    return memories.search(
        filters={"group_id": group_id},
        query=query,
        method="vector",
        memory_types=["episodic_memory", "profile"],
        top_k=10,
    )

# Search team discussions about databases
result = search_group_memories("team_engineering", "database decision")

Group vs Personal Episodes

EverOS generates two perspectives for group chats:
# Get group-level summary (what the team discussed)
group_memories = memories.search(
    filters={"group_id": "team_engineering"},
    query="project architecture decisions",
    method="vector",
    memory_types=["episodic_memory"],
    top_k=5,
)
# Returns: "The engineering team discussed database options and decided
#          to use PostgreSQL. Bob will prepare the schema by Friday."

# Get personal perspective (what Bob specifically contributed/learned)
personal_memories = memories.search(
    filters={"group_id": "team_engineering", "user_id": "user_bob"},
    query="project architecture decisions",
    method="vector",
    memory_types=["episodic_memory"],
    top_k=5,
)
# Returns: "Bob advocated for PostgreSQL based on team familiarity.
#          He was assigned to create the database schema by Friday."

Use Case: Meeting Memory Bot

Build a bot that joins meetings and provides contextual information.
import time
from everos import EverOS


class MeetingMemoryBot:
    def __init__(self, group_id: str, group_name: str):
        self.client = EverOS()
        self.group_id = group_id
        self.group_name = group_name
        self.bot_id = "bot_meeting_assistant"
        self.group_mem = self.client.v1.memories.group
        self.memories = self.client.v1.memories
        self.msg_counter = 0

    def setup_meeting(self, participants: list, meeting_topic: str):
        """Initialize meeting with group and senders."""
        groups = self.client.v1.groups
        senders = self.client.v1.senders

        # Register group
        groups.create(
            group_id=self.group_id,
            name=self.group_name,
            description=f"Meeting: {meeting_topic}"
        )

        # Register all participants and the bot as senders
        for p in participants:
            senders.create(sender_id=p["user_id"], name=p["name"])
        senders.create(sender_id=self.bot_id, name="Meeting Bot")

        # Store meeting context as the first message
        self._next_msg_id()
        now_ms = int(time.time() * 1000)
        self.group_mem.add(
            group_id=self.group_id,
            messages=[
                {
                    "role": "assistant",
                    "sender_id": self.bot_id,
                    "sender_name": "Meeting Bot",
                    "timestamp": now_ms,
                    "content": (
                        f"Meeting started. Topic: {meeting_topic}. "
                        f"Participants: {', '.join(p['name'] for p in participants)}"
                    ),
                    "message_id": self._next_msg_id(),
                }
            ],
        )

    def _next_msg_id(self) -> str:
        self.msg_counter += 1
        return f"meeting_msg_{self.msg_counter:04d}"

    def record_discussion(self, speaker_id: str, speaker_name: str, content: str):
        """Record a discussion point."""
        now_ms = int(time.time() * 1000)
        self.group_mem.add(
            group_id=self.group_id,
            messages=[
                {
                    "role": "user",
                    "sender_id": speaker_id,
                    "sender_name": speaker_name,
                    "timestamp": now_ms,
                    "content": content,
                    "message_id": self._next_msg_id(),
                }
            ],
        )

    def get_relevant_context(self, topic: str) -> str:
        """Retrieve context relevant to current discussion."""
        resp = self.memories.search(
            filters={"group_id": self.group_id},
            query=topic,
            method="vector",
            memory_types=["episodic_memory"],
            top_k=5,
        )

        results = resp.get("result", {}).get("memories", [])
        if not results:
            return "No relevant past discussions found."

        context_parts = ["Relevant past discussions:"]
        for mem in results:
            context_parts.append(f"- {mem.get('memory_content', '')}")

        return "\n".join(context_parts)

    def end_meeting(self):
        """Flush group memory to trigger extraction."""
        self.group_mem.flush(group_id=self.group_id)


# Usage
bot = MeetingMemoryBot("meeting_sprint_planning_2024_01", "Sprint Planning")

bot.setup_meeting(
    participants=[
        {"user_id": "user_alice", "name": "Alice"},
        {"user_id": "user_bob", "name": "Bob"},
    ],
    meeting_topic="Q1 Sprint Planning"
)

# During meeting
bot.record_discussion("user_alice", "Alice", "We should prioritize the auth refactor this sprint.")
bot.record_discussion("user_bob", "Bob", "Agreed. I can take the backend portion.")

# Get context when needed
context = bot.get_relevant_context("authentication system")
print(context)  # Shows past discussions about auth

# End meeting and trigger memory extraction
bot.end_meeting()

Best Practices

Use meaningful, hierarchical group IDs for better organization.
# Good: Hierarchical naming
group_id = "team_engineering_sprint_2024_01"
group_id = "project_phoenix_standup"
group_id = "meeting_quarterly_review_2024_q1"

# Avoid: Generic names
group_id = "chat_1"  # Not descriptive
Every group message must include sender_id and sender_name. Use millisecond timestamps.
import time

message = {
    "role": "user",
    "sender_id": "user_alice",
    "sender_name": "Alice",
    "timestamp": int(time.time() * 1000),
    "content": "The message text here.",
    "message_id": "unique_msg_id",
}
Call flush() when a topic naturally ends to help EverOS extract clean memory boundaries.
group_mem = client.v1.memories.group

# After a discussion topic wraps up
group_mem.flush(group_id="team_engineering")

Next Steps

Customer Support

Apply group memory to support ticket contexts

Batch Processing

Import existing chat history at scale