Add clone chat session feature #158

Closed
opened 2025-12-26 23:20:38 +00:00 by rwachters · 0 comments
rwachters commented 2025-12-26 23:20:38 +00:00 (Migrated from github.com)

Feature Description

Add a "Clone" action to the session actions menu that allows users to duplicate an existing chat session with all its messages, tool calls, and configuration.

Requirements

  • Add "Clone" button to the session actions menu (SessionItemActionsDropdown)
  • Show a dialog allowing the user to customize the cloned session name
  • Default name should be "{original name} (Copy)"
  • Create a new session with:
    • New ID
    • Same messages (with new IDs, preserving thread structure)
    • Same tool calls (with new IDs, mapped to new message IDs)
    • Same owner
    • Same current leaf message (mapped to new ID)
    • Same configured tools
    • Same LLM model
    • Same settings
    • Same group assignment
    • Preserved timestamps (createdAt/updatedAt from original messages)

Implementation Steps

1. Add Clone Dialog UI

  • Create SessionListDialogState.CloneSession variant in SessionListViewModel
  • Add showCloneSessionDialog(session) and updateDialogCloneName(name) functions
  • Include fields: sessionId, defaultName, nameInput, onNameInputChange, onCloneConfirm, onDismiss

2. Add Clone Action to UI Layers

  • Insert "Clone" menu item in SessionItemActionsDropdown (SessionListItem.kt)
  • Add onClone to DialogActions interface
  • Add onShowCloneSessionDialog to SessionListActions interface
  • Wire through to ViewModel
  • Create dialog composable in Dialogs.kt

3. Implement ViewModel Clone Logic

  • Add private cloneSession(sessionId, newName) function in SessionListViewModel
  • Call sessionRepository.cloneSession
  • Handle errors via notificationService
  • Select the new session on success
  • Close dialog

4. Add Repository and API Methods

  • Add suspend fun cloneSession(sessionId: Long, request: CloneSessionRequest): Either<RepositoryError, ChatSession> to SessionRepository
  • Create CloneSessionRequest(name: String) data class in common/models/api/core
  • Add Clone nested resource in SessionResource.kt
  • Implement API client method

5. Implement Server Endpoint and Service

  • Add POST route for SessionResource.ById.Clone in session routes
  • Create CloneSessionError sealed interface (SessionNotFound, InvalidName)
  • Add suspend fun cloneSession(id: Long, userId: Long, name: String): Either<CloneSessionError, ChatSession> to SessionService
  • Implement in SessionServiceImpl with authorization check

6. Implement Service-Level Cloning Logic

In SessionServiceImpl.cloneSession:

  • Validate name is not blank
  • Verify user owns original session (via SessionOwnershipDao.getOwner)
  • Load original session (sessionDao.getSessionById)
  • Create new session with same config (sessionDao.insertSession)
  • Set owner (sessionOwnershipDao.setOwner)
  • Load and clone messages (messageDao.getMessagesBySessionId + repeated insertMessage)
    • Build oldId→newId mapping
    • Preserve parent/child relationships
    • Preserve original timestamps
  • Update new session's currentLeafMessageId to mapped value
  • Clone tool calls (toolCallDao.getToolCallsBySessionId + repeated inserts)
    • Use mapped message IDs
    • Preserve original status
  • Copy tool configs (sessionToolConfigDao.getEnabledToolsForSession + setToolsEnabledForSession)
  • All operations in single transaction for atomicity

Technical Notes

  • Use existing DAO methods (no batch insert methods for now)
  • Entire clone operation must be in a single transaction
  • Authorization check: verify user owns original session before cloning
  • Foreign key constraints ensure group ID validity
  • Message timestamps should be preserved from original

Frontend

  • app/src/commonMain/kotlin/eu/torvian/chatbot/app/viewmodel/SessionListViewModel.kt
  • app/src/commonMain/kotlin/eu/torvian/chatbot/app/compose/sessionlist/SessionListItem.kt
  • app/src/commonMain/kotlin/eu/torvian/chatbot/app/compose/sessionlist/SessionListActions.kt
  • app/src/commonMain/kotlin/eu/torvian/chatbot/app/compose/sessionlist/DialogActions.kt
  • app/src/commonMain/kotlin/eu/torvian/chatbot/app/repository/SessionRepository.kt

Common

  • common/src/commonMain/kotlin/eu/torvian/chatbot/common/api/resources/SessionResource.kt
  • common/src/commonMain/kotlin/eu/torvian/chatbot/common/models/api/core/ (new CloneSessionRequest)

Backend

  • server/src/main/kotlin/eu/torvian/chatbot/server/service/core/SessionService.kt
  • server/src/main/kotlin/eu/torvian/chatbot/server/service/core/impl/SessionServiceImpl.kt
  • server/src/main/kotlin/eu/torvian/chatbot/server/service/core/error/session/ (new CloneSessionError)
  • server/src/main/kotlin/eu/torvian/chatbot/server/ktor/routes/ (session routes)
## Feature Description Add a "Clone" action to the session actions menu that allows users to duplicate an existing chat session with all its messages, tool calls, and configuration. ## Requirements - Add "Clone" button to the session actions menu (SessionItemActionsDropdown) - Show a dialog allowing the user to customize the cloned session name - Default name should be "{original name} (Copy)" - Create a new session with: - New ID - Same messages (with new IDs, preserving thread structure) - Same tool calls (with new IDs, mapped to new message IDs) - Same owner - Same current leaf message (mapped to new ID) - Same configured tools - Same LLM model - Same settings - Same group assignment - Preserved timestamps (createdAt/updatedAt from original messages) ## Implementation Steps ### 1. Add Clone Dialog UI - Create `SessionListDialogState.CloneSession` variant in SessionListViewModel - Add `showCloneSessionDialog(session)` and `updateDialogCloneName(name)` functions - Include fields: sessionId, defaultName, nameInput, onNameInputChange, onCloneConfirm, onDismiss ### 2. Add Clone Action to UI Layers - Insert "Clone" menu item in SessionItemActionsDropdown (SessionListItem.kt) - Add `onClone` to DialogActions interface - Add `onShowCloneSessionDialog` to SessionListActions interface - Wire through to ViewModel - Create dialog composable in Dialogs.kt ### 3. Implement ViewModel Clone Logic - Add private `cloneSession(sessionId, newName)` function in SessionListViewModel - Call `sessionRepository.cloneSession` - Handle errors via notificationService - Select the new session on success - Close dialog ### 4. Add Repository and API Methods - Add `suspend fun cloneSession(sessionId: Long, request: CloneSessionRequest): Either<RepositoryError, ChatSession>` to SessionRepository - Create `CloneSessionRequest(name: String)` data class in common/models/api/core - Add `Clone` nested resource in SessionResource.kt - Implement API client method ### 5. Implement Server Endpoint and Service - Add POST route for `SessionResource.ById.Clone` in session routes - Create `CloneSessionError` sealed interface (SessionNotFound, InvalidName) - Add `suspend fun cloneSession(id: Long, userId: Long, name: String): Either<CloneSessionError, ChatSession>` to SessionService - Implement in SessionServiceImpl with authorization check ### 6. Implement Service-Level Cloning Logic In SessionServiceImpl.cloneSession: - Validate name is not blank - Verify user owns original session (via SessionOwnershipDao.getOwner) - Load original session (sessionDao.getSessionById) - Create new session with same config (sessionDao.insertSession) - Set owner (sessionOwnershipDao.setOwner) - Load and clone messages (messageDao.getMessagesBySessionId + repeated insertMessage) - Build oldId→newId mapping - Preserve parent/child relationships - Preserve original timestamps - Update new session's currentLeafMessageId to mapped value - Clone tool calls (toolCallDao.getToolCallsBySessionId + repeated inserts) - Use mapped message IDs - Preserve original status - Copy tool configs (sessionToolConfigDao.getEnabledToolsForSession + setToolsEnabledForSession) - All operations in single transaction for atomicity ## Technical Notes - Use existing DAO methods (no batch insert methods for now) - Entire clone operation must be in a single transaction - Authorization check: verify user owns original session before cloning - Foreign key constraints ensure group ID validity - Message timestamps should be preserved from original ## Related Files ### Frontend - app/src/commonMain/kotlin/eu/torvian/chatbot/app/viewmodel/SessionListViewModel.kt - app/src/commonMain/kotlin/eu/torvian/chatbot/app/compose/sessionlist/SessionListItem.kt - app/src/commonMain/kotlin/eu/torvian/chatbot/app/compose/sessionlist/SessionListActions.kt - app/src/commonMain/kotlin/eu/torvian/chatbot/app/compose/sessionlist/DialogActions.kt - app/src/commonMain/kotlin/eu/torvian/chatbot/app/repository/SessionRepository.kt ### Common - common/src/commonMain/kotlin/eu/torvian/chatbot/common/api/resources/SessionResource.kt - common/src/commonMain/kotlin/eu/torvian/chatbot/common/models/api/core/ (new CloneSessionRequest) ### Backend - server/src/main/kotlin/eu/torvian/chatbot/server/service/core/SessionService.kt - server/src/main/kotlin/eu/torvian/chatbot/server/service/core/impl/SessionServiceImpl.kt - server/src/main/kotlin/eu/torvian/chatbot/server/service/core/error/session/ (new CloneSessionError) - server/src/main/kotlin/eu/torvian/chatbot/server/ktor/routes/ (session routes)
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#158
No description provided.