Skip to content

Conversation

@anyxling
Copy link
Contributor

Description

This is to improve the functionality of chat history:

  1. Merge user input, AQL query, result into one single entry in the chat history to save space in the DB
  2. Support user feedback to further guide AQL generation

Type of Change

  • New feature
  • Bug fix
  • Breaking change
  • Project configuration change

Complexity

Note

Please provide an estimated complexity of this PR of either Low, Medium or High

How Has This Been Tested?

  • Unit tests
  • Integration tests
  • Manual tests

Checklist

  • Unit tests updated
  • Integration tests updated
  • CHANGELOG.md updated

@anyxling anyxling requested a review from aMahanna August 20, 2025 02:25
@anyxling anyxling self-assigned this Aug 20, 2025
Comment on lines 176 to 179
def add_doc(self, doc: dict[str, Any]) -> None:
"""Add a dict of message to the chat history."""
self._db.insert_document(self._collection_name, doc)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's consider introducing a function called add_qa_message which is used specifically for ArangoGraphQAChain purposes.

When we do this, we can the role property set to "qa, e.g:

{
    "_key": "...",
    "role": "qa",
    "user_input": user_input,
     "aql_query": aql_query,
      "result": result.content
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would allow us to slightly optimize the AQL query to look like this:

FOR doc IN {collection_name}
    FILTER doc.role == "qa"
    SORT doc._key DESC
    LIMIT @n
    RETURN doc

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Idea: Maybe use type instead of role? This would require modifying the other message insertions to include a new type property...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Idea: Better yet, we can introduce a get_messages_by_role method in ChatHistory that accepts n and role as the parameters

Comment on lines 435 to 440
aql = f"""
FOR doc IN {collection_name}
SORT doc._key DESC
LIMIT @n
RETURN UNSET(doc, ["_id", "_key", "_rev", "session_id"])
"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small adjustment to this query, could we wrap this in def get_messages_by_role and store it in the ChatHistory class?

Suggested change
aql = f"""
FOR doc IN {collection_name}
SORT doc._key DESC
LIMIT @n
RETURN UNSET(doc, ["_id", "_key", "_rev", "session_id"])
"""
aql = f"""
FOR doc IN {collection_name}
FILTER doc.session_id == @session_id
AND doc.role == @role
SORT doc._key DESC
LIMIT @n
RETURN UNSET(doc, ["_id", "_key", "_rev", "session_id"])
"""
if include_history:
    chat_history.extend(self.chat_history_store.get_messages_by_role("qa"))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realized the reason I didn't wrap this in get_messages_by_role() here is because we want to include all messages i.e. both qa and human message(feedback). Then I thought of wrapping this with messages() but it wouldn't recognize qa message as it's not BaseMessage instance.

Therefore, I add get_messages() that optionally takes a role argument. If role is given, it retrieves messages by role otherwise it returns all messages. What do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense agreed! Thanks

},
)

def add_qa_message(self, user_input: str, aql_query: str, result: str) -> None:
Copy link
Member

@aMahanna aMahanna Aug 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for both add_message and add_qa_message, can we introduce a new property added to all documents called time?

import time

....

self._db.collection(self._collection_name).insert(
    {
          ...,
          "time": time.time()
     }
)

" Use the 'add_messages' instead."
)

def get_messages(self, role: Optional[str] = None, n_messages: int = 10) -> list:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you good call - slight adjustment to the signature and the AQL query:

def get_messages(self, role: Optional[str] = None, n_messages: int = 10, excluded_fields: list[str] = ["_id", "_key", "_rev", "session_id"]) -> list:
        """Retrieve messages from ArangoDB, optionally filtered by role."""
        query = f"""
            FOR doc IN @@col
                FILTER doc.session_id == @session_id
                {"AND doc.role == @role" if role else ""}
                SORT doc.time DESC
                LIMIT @n
                RETURN UNSET(doc, @excluded_fields)
        """
        bind_vars = {
            "@col": self._collection_name,
            "session_id": self._session_id,
            "role": role,
            "n": n_messages,
            "excluded_fields": excluded_fields,
        }

for msg in self.chat_history_store.messages[-max_history_messages:]:
cls = HumanMessage if msg.type == "human" else AIMessage
chat_history.append(cls(content=msg.content))
chat_history.extend(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch on not passing role here since we also want to include human messages

)

def add_qa_message(self, user_input: str, aql_query: str, result: str) -> None:
"""Add a QA message to the chat history."""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we add the full docstring to this function, i.e :param and :type statements

n_messages: int = 10,
excluded_fields: list[str] = ["_id", "_key", "_rev", "session_id", "time"],
) -> list:
"""Retrieve messages from ArangoDB, optionally filtered by role."""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment as above ^

Copy link
Member

@aMahanna aMahanna left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Small adjustment to the new docstrings, but feel free to merge when those are implemented and the CI passes

@anyxling anyxling merged commit c477c76 into main Aug 29, 2025
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants