Add "Branch & Continue" action to continue conversation from any message #152

Closed
opened 2025-12-26 03:49:01 +00:00 by rwachters · 0 comments
rwachters commented 2025-12-26 03:49:01 +00:00 (Migrated from github.com)

Feature Request: Branch & Continue Action

Add a "Branch & Continue" button to the message actions menu that continues the conversation from any message by sending the thread context (up to that message) to the LLM without creating a new user message. For leaf messages, this continues where it left off; for non-leaf messages, this creates a new sibling assistant message (a new branch).

Use Cases

  • Continue from user message: Regenerates the assistant response (similar to "Regenerate" but available on any message in the thread)
  • Continue from assistant message: Asks the LLM for another response, continuing the conversation

Implementation Plan

Backend Changes

  1. Modify ProcessNewMessageRequest (common/src/commonMain/.../ProcessNewMessageRequest.kt)

    • Make content field nullable (content: String?)
    • Update kdoc to explain that null content means "continue from parent without creating a new user message"
  2. Refactor buildContext method in ChatServiceImpl (server/src/main/.../ChatServiceImpl.kt)

    • Change signature from buildContext(userMessage: ChatMessage.UserMessage, ...) to buildContext(startingMessageId: Long, ...)
    • Look up the message from the map and traverse upward from it
    • This makes the function work for any message type, not just user messages
  3. Update processNewMessage and processNewMessageStreaming in ChatServiceImpl

    • Conditionally call saveUserMessage only when content != null
    • When content is null, set lastMessageId = parentMessageId!! (non-null assertion since validation ensures it)
    • Call buildContext(parentMessageId, ...) instead of buildContext(userMessage, ...)
  4. Update ChatService interface signatures

    • Change content: String parameter to content: String? for both processNewMessage and processNewMessageStreaming
  5. Add validation in validateProcessNewMessageRequest

    • Ensure that when content == null, parentMessageId must not be null
    • Raise ValidateNewMessageError.ModelConfigurationError with appropriate message if validation fails

Frontend Changes

  1. Add onBranchAndContinue callback to MessageActions data class

    • Signature: val onBranchAndContinue: (ChatMessage) -> Unit
  2. Add BranchAndContinueMenuItem composable in MessageActionRow.kt

    • Place in the MoreActionsMenu dropdown
    • Use Icons.Default.PlayArrow icon (or consider Icons.Default.CallSplit, Icons.AutoFixHigh)
    • Text: "Branch & Continue"
    • Call messageActions.onBranchAndContinue(message) on click
  3. Add onBranchAndContinue method to ChatAreaActions interface

    • Implement in ChatScreen.kt to call chatViewModel.branchAndContinue(message)
    • Wire up in ChatArea.kt to pass onBranchAndContinue = actions::onBranchAndContinue
  4. Create BranchAndContinueUseCase

    • Location: app/src/commonMain/.../viewmodel/chat/usecase/BranchAndContinueUseCase.kt
    • Dependencies: ChatState, SessionRepository, NotificationService
    • Send ProcessNewMessageRequest with content = null and parentMessageId = message.id
    • Reuse streaming/non-streaming logic similar to SendMessageUseCase
  5. Add method to ChatViewModel

    • fun branchAndContinue(message: ChatMessage) that calls the use case
    • Set sending state to true/false similar to regular message sending
  6. Wire up dependency injection in Koin app module

    • Add BranchAndContinueUseCase to ChatViewModel factory parameters

UI/UX Considerations

  • Icon: Use Icons.Default.PlayArrow for a clean "continue/play" metaphor
  • Tooltip: Keep consistent as "Branch & Continue" for all message types
  • Loading state: Show the same loading/sending indicators as regular message sending
  • Auto-switch branch: After continuation completes, automatically switch to view the new assistant response
  • Availability: Enable for both user and assistant messages

Technical Notes

  • The server's buildContext function already traverses from any message up to the root, building the conversation thread
  • When content is null, no new user message is created - the assistant responds directly based on the existing thread context
  • For leaf messages, this effectively continues the conversation
  • For non-leaf messages, this creates a new sibling (branching behavior)

Testing Checklist

  • Backend validation: content=null requires non-null parentMessageId
  • Backend: buildContext works with message ID instead of UserMessage object
  • Backend: Streaming mode works without creating user message
  • Backend: Non-streaming mode works without creating user message
  • Frontend: Button appears in more actions menu
  • Frontend: Action works on user messages (regenerates response)
  • Frontend: Action works on assistant messages (continues conversation)
  • Frontend: Loading states appear correctly
  • Frontend: Branch switching happens after completion
  • Integration: Tool calling works in continue mode
  • Integration: Streaming works in continue mode
## Feature Request: Branch & Continue Action Add a "Branch & Continue" button to the message actions menu that continues the conversation from any message by sending the thread context (up to that message) to the LLM without creating a new user message. For leaf messages, this continues where it left off; for non-leaf messages, this creates a new sibling assistant message (a new branch). ### Use Cases - **Continue from user message**: Regenerates the assistant response (similar to "Regenerate" but available on any message in the thread) - **Continue from assistant message**: Asks the LLM for another response, continuing the conversation ### Implementation Plan #### Backend Changes 1. **Modify `ProcessNewMessageRequest`** (`common/src/commonMain/.../ProcessNewMessageRequest.kt`) - Make `content` field nullable (`content: String?`) - Update kdoc to explain that null content means "continue from parent without creating a new user message" 2. **Refactor `buildContext` method** in `ChatServiceImpl` (`server/src/main/.../ChatServiceImpl.kt`) - Change signature from `buildContext(userMessage: ChatMessage.UserMessage, ...)` to `buildContext(startingMessageId: Long, ...)` - Look up the message from the map and traverse upward from it - This makes the function work for any message type, not just user messages 3. **Update `processNewMessage` and `processNewMessageStreaming`** in `ChatServiceImpl` - Conditionally call `saveUserMessage` only when `content != null` - When content is null, set `lastMessageId = parentMessageId!!` (non-null assertion since validation ensures it) - Call `buildContext(parentMessageId, ...)` instead of `buildContext(userMessage, ...)` 4. **Update `ChatService` interface** signatures - Change `content: String` parameter to `content: String?` for both `processNewMessage` and `processNewMessageStreaming` 5. **Add validation** in `validateProcessNewMessageRequest` - Ensure that when `content == null`, `parentMessageId` must not be null - Raise `ValidateNewMessageError.ModelConfigurationError` with appropriate message if validation fails #### Frontend Changes 6. **Add `onBranchAndContinue` callback** to `MessageActions` data class - Signature: `val onBranchAndContinue: (ChatMessage) -> Unit` 7. **Add `BranchAndContinueMenuItem` composable** in `MessageActionRow.kt` - Place in the `MoreActionsMenu` dropdown - Use `Icons.Default.PlayArrow` icon (or consider `Icons.Default.CallSplit`, `Icons.AutoFixHigh`) - Text: "Branch & Continue" - Call `messageActions.onBranchAndContinue(message)` on click 8. **Add `onBranchAndContinue` method** to `ChatAreaActions` interface - Implement in `ChatScreen.kt` to call `chatViewModel.branchAndContinue(message)` - Wire up in `ChatArea.kt` to pass `onBranchAndContinue = actions::onBranchAndContinue` 9. **Create `BranchAndContinueUseCase`** - Location: `app/src/commonMain/.../viewmodel/chat/usecase/BranchAndContinueUseCase.kt` - Dependencies: `ChatState`, `SessionRepository`, `NotificationService` - Send `ProcessNewMessageRequest` with `content = null` and `parentMessageId = message.id` - Reuse streaming/non-streaming logic similar to `SendMessageUseCase` 10. **Add method to `ChatViewModel`** - `fun branchAndContinue(message: ChatMessage)` that calls the use case - Set sending state to true/false similar to regular message sending 11. **Wire up dependency injection** in Koin app module - Add `BranchAndContinueUseCase` to ChatViewModel factory parameters ### UI/UX Considerations - **Icon**: Use `Icons.Default.PlayArrow` for a clean "continue/play" metaphor - **Tooltip**: Keep consistent as "Branch & Continue" for all message types - **Loading state**: Show the same loading/sending indicators as regular message sending - **Auto-switch branch**: After continuation completes, automatically switch to view the new assistant response - **Availability**: Enable for both user and assistant messages ### Technical Notes - The server's `buildContext` function already traverses from any message up to the root, building the conversation thread - When content is null, no new user message is created - the assistant responds directly based on the existing thread context - For leaf messages, this effectively continues the conversation - For non-leaf messages, this creates a new sibling (branching behavior) ### Testing Checklist - [ ] Backend validation: content=null requires non-null parentMessageId - [ ] Backend: buildContext works with message ID instead of UserMessage object - [ ] Backend: Streaming mode works without creating user message - [ ] Backend: Non-streaming mode works without creating user message - [ ] Frontend: Button appears in more actions menu - [ ] Frontend: Action works on user messages (regenerates response) - [ ] Frontend: Action works on assistant messages (continues conversation) - [ ] Frontend: Loading states appear correctly - [ ] Frontend: Branch switching happens after completion - [ ] Integration: Tool calling works in continue mode - [ ] Integration: Streaming works in continue mode
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Torvian.eu/chatbot#152
No description provided.