Conversation Model
Conversations are the primary interface between users and agents on the XpressAI Platform. They are not just chat logs --- they are structured entities with participant management, dispatch rules, deduplication, and read-state tracking. Understanding how conversations work is important for building agents that behave correctly in group settings, for debugging message delivery, and for reasoning about what an agent "sees" when it responds.
Conversation Types
The platform supports three types of conversations, each with different dispatch semantics.
| Type | Participants | Agent behavior |
|---|---|---|
| Group | Multiple users + multiple agents | Only mentioned agents respond (via @agent) |
| DM (Direct Message) | Two users | No agent involvement |
| Agent DM | One user + one agent | Agent always responds to every message |
The conversation type determines how the platform decides which agents to activate when a message is posted.
Conversation Keys
Every conversation has a conversation key that determines its scope and uniqueness.
| Key pattern | Scope | Example use case |
|---|---|---|
global | Project-wide | A shared team channel |
per_room | Tied to a specific room/context | A conversation scoped to a particular feature, topic, or UI context (a "room" is any named scope that groups related conversations -- for example, a task detail page or a specific channel) |
direct_message | Between two specific participants | Private user-to-user or user-to-agent chat |
The conversation key, combined with the project ID and participant IDs, uniquely identifies a conversation. This means the same two users in the same project always return to the same DM thread rather than creating new ones.
Message Dispatch Flow
When a user posts a message, the platform does not simply broadcast it. It follows a structured dispatch process.
Mentions and Group Conversations
In group conversations with multiple agents, the platform uses @mentions to determine which agents respond. This prevents every agent from replying to every message, which would be chaotic.
@toby can you research this?--- only the agent named "toby" receives the message for processing.Hey team, good morning!--- no agents are dispatched because none are mentioned.
In Agent DM conversations, mentions are not required. The agent is the only other participant, so it always responds.
The mention-based dispatch for group conversations was a deliberate choice. Early versions dispatched to all agent participants on every message, which led to agents talking over each other and generating confusing, expensive multi-agent responses to casual messages. Mentions give users explicit control over which agent engages.
Deduplication
Messages can be re-delivered to an agent's queue due to the NACK/requeue mechanism in the Agent Messaging System. The deduplication layer prevents duplicate processing.
Before dispatching a message to an agent:
- The platform checks the deduplication table for this message ID + agent combination.
- If an entry exists, the message has already been dispatched and is skipped.
- If no entry exists, the dispatch proceeds and the entry is recorded.
This is especially important for preventing duplicate side effects. Without deduplication, a redelivered message could cause an agent to send the same email twice or create duplicate tasks.
There is also execution-level deduplication in the messaging system. The dispatch-level deduplication described here prevents the same message from being sent to an agent's queue twice, while execution-level deduplication prevents duplicate tool executions within the NACK/requeue loop. See Agent Messaging System for details.
History Window
Agents have limited context. When the platform builds the prompt for an agent, it includes only the last N messages from the conversation. The default window size is 50 messages.
This means:
- In a long conversation, the agent does not see the first messages.
- Critical context from early in a conversation may need to be restated or stored in the agent's memory.
- The history window is a trade-off between context richness and token cost.
Older messages are not lost --- they remain in the database and can be accessed through the agent's mid-term memory (Vecto semantic search). But they are not included in the direct LLM prompt. See Agent Messaging System for more details on how the history window is managed.
The default of 50 messages balances context quality with cost. Most conversations have their most relevant context in the recent messages. For long-running conversations, the agent's memory system fills the gap by surfacing semantically relevant older messages.
Read State
The platform tracks read state per user per conversation. This powers:
- Unread message counts in the sidebar.
- "New messages" indicators when returning to a conversation.
- The "mark as read" action when a user views a conversation.
Read state is updated when a user opens a conversation or scrolls to the bottom. It is stored as a timestamp of the last-read message, which makes the unread count calculation a simple query for messages after that timestamp.
Typing Indicators
When an agent is processing a message (calling the LLM, executing tools), the platform broadcasts typing indicators to the conversation participants via SSE (Server-Sent Events). This gives users visual feedback that the agent is working on a response, similar to the "typing..." indicator in consumer messaging apps.
Typing indicators are ephemeral --- they are not persisted to the database. They exist only in the SSE stream and disappear when the agent's response arrives or the connection is closed.
How It All Connects
The conversation model sits at the intersection of several platform systems:
- Agent Messaging System: conversations create the RabbitMQ queues that agents consume from.
- Task Execution Lifecycle: a conversation interaction can spawn a background task via
continue_as_task. - Knowledge & Memory: the history window feeds into short-term memory, while older messages feed into mid-term memory via Vecto.
- Org, Workspace & Project Hierarchy: conversations are scoped to projects, and participant access follows project membership.