How ConversationManager Handles Conversation History and Maintains Context Across Interactions
The ConversationManager stitches together chronological message logs and semantically similar past exchanges to provide full conversational background for every LLM request, storing each turn as embedded MessageData records via the VectorStorageProvider interface.
In the heurist-network/heurist-agent-framework, the ConversationManager serves as the central orchestration component that handles conversation history through a pipeline of retrieval, augmentation, and persistence operations. Located in core/components/conversation_manager.py, it ensures that every new LLM call receives both the exact sequence of prior exchanges and relevant semantically similar dialogues from any chat session.
Three-Stage Context Retrieval Pipeline
The manager implements a three-stage pipeline that processes conversation history before each LLM inference. Each stage corresponds to a specific method in core/components/conversation_manager.py.
Retrieving Chronological History with get_conversation_context
When a new request arrives, the get_conversation_context(chat_id, limit) method queries the underlying message store for the most recent agent-response entries belonging to the same chat_id. The implementation fetches raw rows and sorts them by timestamp in descending order, then reverses the list to obtain strict chronological order. Each stored pair is formatted into a conversational string:
User: <original_query>
Assistant: <message>
This block is prefixed with a header indicating it represents the conversation history, providing the LLM with the exact sequence of prior turns for that specific session.
Augmenting with Semantic Similarity via get_similar_messages
For richer grounding beyond sequential logs, get_similar_messages(embedding, chat_id, threshold, limit) performs a vector similarity search. The method computes the cosine similarity between the current query's embedding and stored user-message embeddings, returning records where similarity meets or exceeds the threshold parameter (typically ≥ 0.85).
For each matching user message, the manager retrieves the corresponding agent-response and constructs a "Related previous conversations" block that includes the similar question, the past answer, and the similarity score. This section explicitly advises the model to provide a fresh perspective, preventing verbatim repetition while leveraging relevant context from any historical chat.
Persisting Turns Through store_interaction
After the LLM generates a response, store_interaction(message, response, chat_id, metadata) persists the complete turn. The implementation:
- Embeds the user message via
get_embedding()and stores it as aMessageDatarecord withmessage_type="user_message" - Embeds the assistant reply and stores it as a
MessageDatarecord withmessage_type="agent_response", maintaining a reference to the original query and its embedding
Both records are written immediately to the message_store, making them available for subsequent context building operations.
Storage Architecture and the VectorStorageProvider Interface
The ConversationManager delegates storage operations to an implementation of the abstract VectorStorageProvider interface defined in core/embedding.py. This provider supplies two critical operations:
find_messages(...): Fetches raw rows filtered by message type and chat ID, used byget_conversation_contextto build chronological logsfind_similar_messages(embedding, ...): Executes vector-similarity queries against stored embeddings, powering the semantic retrieval inget_similar_messages
The concrete PostgresVectorStorage class provides the production implementation, utilizing PostgreSQL with pgvector extension to store MessageData objects and perform efficient similarity searches.
Implementation Example
from core.components.conversation_manager import ConversationManager
from core.embedding import PostgresVectorStorage, PostgresConfig
# Initialize PostgreSQL storage backend
pg_cfg = PostgresConfig(
host="localhost",
port=5432,
database="heurist",
user="heurist_user",
password="***",
table_name="messages",
)
store = PostgresVectorStorage(pg_cfg)
store.initialize()
# Instantiate the conversation manager
conv_mgr = ConversationManager(message_store=store)
# Process a new user query
chat_id = "session-42"
user_msg = "How do I reset my API key?"
# 1. Retrieve chronological history
history_ctx = await conv_mgr.get_conversation_context(chat_id, limit=10)
# 2. Compute embedding and find similar messages
embedding = conv_mgr.get_embedding(user_msg)
similar_ctx = await conv_mgr.get_similar_messages(
embedding, chat_id=chat_id, threshold=0.85, limit=3
)
# 3. Construct complete prompt for LLM
full_prompt = f"{history_ctx}{similar_ctx}\nUser: {user_msg}\nAssistant:"
# Submit full_prompt to LLM client...
# 4. Store the interaction after receiving response
assistant_reply = "You can reset your API key from the dashboard..."
metadata = {
"source_interface": "web",
"tool_call": None,
"response_type": "text",
"key_topics": ["api-key", "reset"],
}
await conv_mgr.store_interaction(user_msg, assistant_reply, chat_id, metadata)
The same ConversationManager instance safely handles multiple concurrent chats, with each operation isolating history by unique chat_id values.
Summary
- Chronological retrieval:
get_conversation_contextqueriesmessage_storefor recent agent responses bychat_id, sorting by timestamp to maintain exact conversational sequence - Semantic augmentation:
get_similar_messagesleverages vector embeddings and cosine similarity to surface relevant historical exchanges across all chats - Persistent storage:
store_interactionembeds and saves both user queries and assistant responses asMessageDatarecords immediately after generation - Storage abstraction: The manager depends on
VectorStorageProvider(typicallyPostgresVectorStorage) for both exact filtering and similarity search operations - Session isolation: All history operations are scoped to specific
chat_idparameters, enabling multi-tenancy without cross-contamination
Frequently Asked Questions
How does ConversationManager isolate different chat sessions?
The manager uses the chat_id parameter as a mandatory filter in get_conversation_context and get_similar_messages, ensuring that chronological history only pulls records matching the specific session identifier. While semantic similarity searches can optionally query across all chats, the primary conversation flow remains strictly partitioned by chat_id.
What is the role of embeddings in conversation history?
Embeddings enable semantic retrieval beyond exact keyword matching. When store_interaction saves a turn, both the user message and agent response are embedded using the get_embedding function. These vectors allow find_similar_messages to compute cosine similarity between the current query and historical messages, surfacing conceptually related conversations even when phrasing differs significantly.
Which storage backends are compatible with ConversationManager?
The manager requires any class implementing the VectorStorageProvider abstract interface from core/embedding.py. The reference implementation uses PostgresVectorStorage, which requires PostgreSQL with the pgvector extension. Custom implementations must provide find_messages() for filtered retrieval and find_similar_messages() for vector similarity search.
How does similarity-based context differ from chronological history?
Chronological history provides the exact sequence of prior exchanges within the same chat_id, ensuring continuity and turn-taking coherence. Similarity-based context retrieves semantically related exchanges from any chat session when their embeddings exceed the similarity threshold, offering relevant background knowledge without requiring the user to have had prior interactions on that specific topic in the current thread.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →