Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions services/llm-api/cmd/server/wire_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 20 additions & 1 deletion services/llm-api/internal/domain/conversation/conversation.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ type ConversationRepository interface {
// TODO: Implement forking functionality for conversation editing
ForkBranch(ctx context.Context, conversationID uint, sourceBranch, newBranch string, fromItemID string, description *string) error

// SwapBranchToMain swaps a branch with MAIN - the given branch becomes MAIN
// and the old MAIN is renamed to a backup branch name. This is used for edit/regenerate
// operations where the new content should become the primary conversation.
SwapBranchToMain(ctx context.Context, conversationID uint, branchToPromote string) (oldMainBackupName string, err error)

// Item rating operations - TODO: Implement item rating/feedback system
RateItem(ctx context.Context, conversationID uint, itemID string, rating ItemRating, comment *string) error
GetItemRating(ctx context.Context, conversationID uint, itemID string) (*ItemRating, error)
Expand Down Expand Up @@ -299,8 +304,22 @@ func (c *Conversation) CreateBranch(newBranchName, sourceBranch, fromItemID stri
return nil
}

// CreateBranchMetadata creates metadata for a new branch
func (c *Conversation) CreateBranchMetadata(name string, parentBranch *string, forkFromItemID *string, description *string) BranchMetadata {
now := time.Now()
return BranchMetadata{
Name: name,
Description: description,
ParentBranch: parentBranch,
ForkedAt: &now,
ForkedFromItemID: forkFromItemID,
ItemCount: 0,
CreatedAt: now,
UpdatedAt: now,
}
}

// GenerateEditBranchName generates a unique branch name for conversation edits
// TODO: Currently unused - will be needed when implementing conversation branching UI
func GenerateEditBranchName(conversationID uint) string {
return fmt.Sprintf("EDIT_%d_%d", conversationID, time.Now().Unix())
}
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,17 @@ func (s *ConversationService) AddItemsToConversation(ctx context.Context, conv *
return []Item{}, nil
}

// Validate branch exists (for now, only MAIN is supported)
// Default to MAIN branch if not specified
if branchName == "" {
branchName = BranchMain
}

// Validate branch exists for non-MAIN branches
if branchName != BranchMain {
return nil, platformerrors.NewError(ctx, platformerrors.LayerDomain, platformerrors.ErrorTypeNotFound, fmt.Sprintf("branch not found: %s", branchName), nil, "e5f6a7b8-c9d0-4e1f-2a3b-4c5d6e7f8a9b")
branch, err := s.repo.GetBranch(ctx, conv.ID, branchName)
if err != nil || branch == nil {
return nil, platformerrors.NewError(ctx, platformerrors.LayerDomain, platformerrors.ErrorTypeNotFound, fmt.Sprintf("branch not found: %s", branchName), nil, "e5f6a7b8-c9d0-4e1f-2a3b-4c5d6e7f8a9b")
}
}
Comment on lines 209 to 214
Copy link

Copilot AI Dec 19, 2025

Choose a reason for hiding this comment

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

The branch existence validation only happens for non-MAIN branches, but the code doesn't verify that the MAIN branch actually exists in the database before adding items to it. If the MAIN branch record is missing (e.g., due to data corruption or migration issues), items could be added without corresponding branch metadata, leading to inconsistent state. Consider validating MAIN branch existence as well, or ensuring MAIN is created during conversation initialization.

Copilot uses AI. Check for mistakes.

// Get current item count to determine starting sequence number
Expand All @@ -229,15 +237,9 @@ func (s *ConversationService) AddItemsToConversation(ctx context.Context, conv *
itemPtrs[i] = &items[i]
}

// Add items to repository
if branchName == BranchMain || branchName == "" {
if err := s.repo.BulkAddItems(ctx, conv.ID, itemPtrs); err != nil {
return nil, platformerrors.AsError(ctx, platformerrors.LayerDomain, err, "failed to add items")
}
} else {
if err := s.repo.BulkAddItemsToBranch(ctx, conv.ID, branchName, itemPtrs); err != nil {
return nil, platformerrors.AsError(ctx, platformerrors.LayerDomain, err, "failed to add items to branch")
}
// Add items to repository - use branch-aware method for all branches
if err := s.repo.BulkAddItemsToBranch(ctx, conv.ID, branchName, itemPtrs); err != nil {
return nil, platformerrors.AsError(ctx, platformerrors.LayerDomain, err, "failed to add items to branch")
}

// Update conversation's updated_at timestamp
Expand Down
1 change: 1 addition & 0 deletions services/llm-api/internal/domain/conversation/item.go
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,7 @@ type ItemFilter struct {
ConversationID *uint
Role *ItemRole
ResponseID *uint
Branch *string // Filter by branch name
}

type ItemRepository interface {
Expand Down
Loading
Loading