Unlocking Conversation Branching in ChatGPT: A Deep Dive
Written on
Chapter 1: Introduction to Conversation Branching
In the world of chatbots, ChatGPT stands out as a uniquely multifaceted tool. While some may view it as an over-hyped chatbot, others recognize its potential for advanced functionalities such as prompt engineering. However, today’s focus shifts away from AI’s broader implications and hones in on JavaScript and its underlying algorithms.
One crucial feature present in many popular chatbots is message editing. This allows users to correct mistakes or redirect conversations. ChatGPT, however, takes this a step further by preserving earlier conversation branches whenever messages are edited—a functionality not commonly found in other chatbots. The complexity of implementing this feature is significant, which is likely why many alternatives shy away from it.
OpenConvo, my adaptation of Chatbot UI v1, incorporates this conversation branching feature, which was my primary motivation for creating the fork. Let’s step into the shoes of OpenAI developers and explore how to implement this functionality within ChatGPT.
Section 1.1: Implementing Message Storage
To enable users to revisit any message sent during the chat, we must modify the chatbot to store both user and AI messages after edits or regenerations. Initially, we’ll maintain a straightforward list of messages, which continuously expands.
The three main functional requirements we need to address, along with their current operations in a sample React application, are:
- Adding a New Message: This involves appending an item to the message list.
- Editing a Message: This requires deleting the message and all subsequent ones, followed by adding a new message with the corrected content.
- Displaying Messages: This transforms the list into a JSX array, mapping your data to UI elements.
Section 1.2: Transitioning to a Tree Structure
With the introduction of the conversation branching feature, we must transition away from simple lists. Each message needs to have sibling messages—messages that share the same level—and a clear parent-child relationship.
To implement this tree-like structure, we can utilize linked lists. Each message acts as a node, starting with a single "head" node. Each node maintains four pointers: prevSibling, nextSibling, parent, and child. This arrangement allows for easy navigation through the conversation tree.
The branching can occur in two ways:
- Branching Right: By editing or regenerating a message.
- Branching Down: By submitting a new message or receiving a response.
The vital algorithm for managing this branching is graph traversal. Below is the pseudocode for traversing the active conversation branch to find the latest message:
Set current node to conversation head (the level 1 node)
Look for the active node at the current node's level and re-set current node to it.
If current node has a child, re-set current node to it. Else, return current node.
Repeat the above steps until completion.
When a user adds a message, we navigate to the latest message and append a child to extend the current branch. If it's a new conversation, we simply establish the head node as this new message.
Chapter 2: Managing Message Edits and Viewing History
The process of editing a message or regenerating a response does not require traversal; instead, we identify the node via the message ID during a "message edited" event. At that node, we can find its latest sibling and add a new sibling.
Displaying messages is straightforward: we traverse down all active nodes in the conversation and extract their information for display purposes. In OpenConvo, each node is added to a simple list for transformation into JSX for the web application.
To enhance the branching feature, users must be able to view previous messages. We can achieve this by adjusting the active message to its left or right sibling, effectively allowing users to navigate through their conversation history.
With these features successfully integrated, we can appreciate the complexities and nuances of conversation branching in ChatGPT. Another well-known method for representing graphs and trees is through an array of lists, which may offer different advantages or challenges in implementation.
To avoid potential pitfalls and save time, check out "Every Crazy Thing JavaScript Does," a guide that delves into the subtleties and lesser-known aspects of JavaScript.
Thank you for joining the In Plain English community! Before you leave, be sure to follow us on various platforms for more insightful content.