# How ConversationManager Handles Conversation History and Maintains Context Across Interactions

> Discover how ConversationManager maintains context across interactions by storing message logs as embedded records. Learn how it uses VectorStorageProvider for full conversational background in LLM requests.

- Repository: [Heurist/heurist-agent-framework](https://github.com/heurist-network/heurist-agent-framework)
- Tags: internals
- Published: 2026-03-03

---

**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`](https://github.com/heurist-network/heurist-agent-framework/blob/main/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`](https://github.com/heurist-network/heurist-agent-framework/blob/main/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:

1. Embeds the user message via `get_embedding()` and stores it as a `MessageData` record with `message_type="user_message"`
2. Embeds the assistant reply and stores it as a `MessageData` record with `message_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`](https://github.com/heurist-network/heurist-agent-framework/blob/main/core/embedding.py). This provider supplies two critical operations:

- **`find_messages(...)`**: Fetches raw rows filtered by message type and chat ID, used by `get_conversation_context` to build chronological logs
- **`find_similar_messages(embedding, ...)`**: Executes vector-similarity queries against stored embeddings, powering the semantic retrieval in `get_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

```python
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_context` queries `message_store` for recent agent responses by `chat_id`, sorting by timestamp to maintain exact conversational sequence
- **Semantic augmentation**: `get_similar_messages` leverages vector embeddings and cosine similarity to surface relevant historical exchanges across all chats
- **Persistent storage**: `store_interaction` embeds and saves both user queries and assistant responses as `MessageData` records immediately after generation
- **Storage abstraction**: The manager depends on `VectorStorageProvider` (typically `PostgresVectorStorage`) for both exact filtering and similarity search operations
- **Session isolation**: All history operations are scoped to specific `chat_id` parameters, 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`](https://github.com/heurist-network/heurist-agent-framework/blob/main/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.