When a conversation takes a wrong turn twenty messages deep — a bad file upload, a misread instruction, a hallucination that the model now treats as ground truth — users need a way to rewind and try a different path without losing the useful context that came before. A strictly linear conversation forces "delete the last ten messages or start a new chat" as the only exits, both of which throw away work. Branching preserves that work.
High because linear-only conversations force users to discard useful context whenever a thread derails.
Start with edit-and-regenerate as the minimum viable branch. When a user edits a prior message, truncate state to that point and call reload() to regenerate from the edited turn. Full tree branching requires a parent_message_id column on the messages table and a tree-rendering sidebar; ship the minimum first. Implement in src/components/chat/message-actions.tsx.
setMessages(messages.slice(0, editIndex).concat({ ...messages[editIndex], content: newContent }))
reload()
ID: ai-ux-patterns.feedback-control.conversation-branching
Severity: high
What to look for: Count all conversation state management patterns in the data model. Enumerate whether the data model supports branching: check for parentMessageId fields, version history on messages, tree-structured state, or edit-and-regenerate handlers. Look for "fork from here", "branch", or "continue from this point" actions on individual messages. At least 1 branching mechanism must exist.
Pass criteria: Users can either (a) branch a conversation from a specific message, creating a parallel thread, or (b) edit a prior user message to create a new continuation (which is a minimal branching implementation). At least 1 branching mechanism must be implemented. Report the count on pass: "Found X branching mechanisms."
Fail criteria: Conversations are entirely linear — no forking, no edit-and-regenerate. Users can only append new messages.
Skip (N/A) when: Same as regeneration-button.
Detail on fail: "Conversation is strictly linear — message state is a flat array with no parentMessageId, no forking UI, and no edit-and-regenerate capability".
Remediation: Full branching is complex. Start with edit-and-regenerate as a minimum viable branching pattern.
For edit-and-regenerate (minimal branching):
const handleEditAndRegenerate = (messageIndex: number, newContent: string) => {
// Keep all messages up to and including the edited user message
const truncated = [
...messages.slice(0, messageIndex),
{ ...messages[messageIndex], content: newContent }
]
setMessages(truncated)
// Trigger regeneration from this point
reload()
}
For full branching, consider a parentId field on messages and a tree-rendering component. This is a larger feature — the Vercel AI SDK useChat hook supports experimental_resume for multi-turn management.