Skip to content

Commit 495dfd4

Browse files
committed
Add Delete message(s) support
Fixes: cristianadam#8
1 parent d76869a commit 495dfd4

8 files changed

Lines changed: 274 additions & 12 deletions

llamachateditor.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,16 @@ ChatEditor::ChatEditor()
156156
&ChatManager::messageExtraUpdated,
157157
this,
158158
&ChatEditor::onMessageExtraUpdated);
159+
connect(&ChatManager::instance(),
160+
&ChatManager::messageDeleted,
161+
this,
162+
[this](const QString &convId) {
163+
if (convId == m_viewingConvId) {
164+
// Refresh the entire view to update the tree
165+
ViewingChat chat = ChatManager::instance().getViewingChat(m_viewingConvId);
166+
refreshMessages(chat.messages, chat.conv.currNode);
167+
}
168+
});
159169

160170
connect(m_input, &ChatInput::sendRequested, this, &ChatEditor::onSendRequested);
161171
connect(m_input, &ChatInput::stopRequested, this, &ChatEditor::onStopRequested);
@@ -425,6 +435,7 @@ void ChatEditor::refreshMessages(const QVector<Message> &messages, qint64 leafNo
425435
connect(w, &ChatMessage::editRequested, this, &ChatEditor::onEditRequested);
426436
connect(w, &ChatMessage::regenerateRequested, this, &ChatEditor::onRegenerateRequested);
427437
connect(w, &ChatMessage::siblingChanged, this, &ChatEditor::onSiblingChanged);
438+
connect(w, &ChatMessage::deleteRequested, this, &ChatEditor::onDeleteMessageRequested);
428439
m_messageLayout->addWidget(w);
429440
m_messageWidgets.append(w);
430441
}
@@ -515,6 +526,7 @@ void ChatEditor::onMessageAppended(const Message &msg, qint64 pendingId)
515526
connect(w, &ChatMessage::editRequested, this, &ChatEditor::onEditRequested);
516527
connect(w, &ChatMessage::regenerateRequested, this, &ChatEditor::onRegenerateRequested);
517528
connect(w, &ChatMessage::siblingChanged, this, &ChatEditor::onSiblingChanged);
529+
connect(w, &ChatMessage::deleteRequested, this, &ChatEditor::onDeleteMessageRequested);
518530

519531
m_messageLayout->addWidget(w);
520532
m_messageWidgets.append(w);
@@ -565,6 +577,7 @@ void ChatEditor::onPendingMessageChanged(const Message &pm)
565577
connect(w, &ChatMessage::editRequested, this, &ChatEditor::onEditRequested);
566578
connect(w, &ChatMessage::regenerateRequested, this, &ChatEditor::onRegenerateRequested);
567579
connect(w, &ChatMessage::siblingChanged, this, &ChatEditor::onSiblingChanged);
580+
connect(w, &ChatMessage::deleteRequested, this, &ChatEditor::onDeleteMessageRequested);
568581

569582
// Insert speed label after the assistant widget
570583
if (settings().showTokensPerSecond.value()) {
@@ -678,6 +691,34 @@ void ChatEditor::onServerPropsUpdated()
678691
}
679692
}
680693

694+
void ChatEditor::onDeleteMessageRequested(const Message &msg)
695+
{
696+
auto [userMessages, assistantMessages] = ChatManager::instance().getBranchStats(msg.convId,
697+
msg.id);
698+
int totalMessages = userMessages + assistantMessages;
699+
if (totalMessages > 1) {
700+
QString warningText = Tr::tr("This will delete %1 messages including: %2 user messages and "
701+
"%3 assistant responses ...")
702+
.arg(totalMessages)
703+
.arg(userMessages)
704+
.arg(assistantMessages);
705+
706+
if (QMessageBox::question(widget(), Tr::tr("Confirm Branch Deletion"), warningText)
707+
!= QMessageBox::Yes) {
708+
return;
709+
}
710+
} else {
711+
if (QMessageBox::question(widget(),
712+
Tr::tr("Delete Message"),
713+
Tr::tr("Are you sure you want to delete this message?"))
714+
!= QMessageBox::Yes) {
715+
return;
716+
}
717+
}
718+
719+
ChatManager::instance().deleteMessageBranch(msg.convId, msg.id);
720+
}
721+
681722
void ChatEditor::startSearch()
682723
{
683724
// Show the floating search toolbar

llamachateditor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ public slots:
6262
void onRegenerateRequested(const LlamaCpp::Message &msg);
6363
void onSiblingChanged(qint64 siblingId);
6464
void onServerPropsUpdated();
65+
void onDeleteMessageRequested(const LlamaCpp::Message &msg);
6566

6667
void startSearch();
6768
void nextSearchResult();

llamachatmanager.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,4 +917,52 @@ void ChatManager::renameConversation(const QString &convId, const QString &name)
917917
m_storage->renameConversation(convId, name);
918918
}
919919

920+
void ChatManager::deleteMessageBranch(const QString &convId, qint64 msgId)
921+
{
922+
if (m_storage->deleteMessageBranch(msgId))
923+
emit messageDeleted(convId);
924+
}
925+
926+
QPair<int, int> ChatManager::getBranchStats(const QString &convId, qint64 msgId) const
927+
{
928+
QPair<int, int> stats{0, 0};
929+
int &userMessages = stats.first;
930+
int &assistantMessages = stats.second;
931+
932+
QVector<Message> allMessages = m_storage->getMessages(convId);
933+
934+
// Map for quick lookup
935+
QHash<qint64, Message> map;
936+
for (const auto &m : std::as_const(allMessages)) {
937+
map.insert(m.id, m);
938+
}
939+
940+
if (!map.contains(msgId))
941+
return stats;
942+
943+
// Traverse the branch using a stack (DFS)
944+
QVector<qint64> stack;
945+
stack.push_back(msgId);
946+
947+
while (!stack.isEmpty()) {
948+
qint64 currentId = stack.takeLast();
949+
if (!map.contains(currentId))
950+
continue;
951+
952+
const Message &m = map[currentId];
953+
if (m.role == "user") {
954+
++userMessages;
955+
} else {
956+
++assistantMessages;
957+
}
958+
959+
// Add children to stack to continue traversal
960+
for (qint64 childId : m.children) {
961+
stack.push_back(childId);
962+
}
963+
}
964+
965+
return stats;
966+
}
967+
920968
} // namespace LlamaCpp

llamachatmanager.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ class ChatManager : public QObject
5555
Conversation createConversation(const QString &name);
5656
void deleteConversation(const QString &convId);
5757
void renameConversation(const QString &convId, const QString &name);
58+
void deleteMessageBranch(const QString &convId, qint64 msgId);
59+
QPair<int,int> getBranchStats(const QString &convId, qint64 msgId) const;
5860

5961
QList<Conversation> allConversations();
6062

@@ -88,6 +90,7 @@ class ChatManager : public QObject
8890
qint64 leafNodeId,
8991
const QStringList &quetions);
9092
void messageExtraUpdated(const LlamaCpp::Message &msg, const QList<QVariantMap> &newExtra);
93+
void messageDeleted(const QString &convId);
9194

9295
private:
9396
explicit ChatManager(QObject *parent = nullptr);

llamachatmessage.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,13 @@ void ChatMessage::buildUI()
222222
connect(m_copyButton, &QToolButton::clicked, this, &ChatMessage::onCopyClicked);
223223
actionLayout->addWidget(m_copyButton);
224224

225+
m_deleteButton = new QToolButton(this);
226+
m_deleteButton->setText("K");
227+
m_deleteButton->setToolTip(Tr::tr("Delete this message"));
228+
m_deleteButton->setVisible(!m_haveToolCalls);
229+
connect(m_deleteButton, &QToolButton::clicked, this, &ChatMessage::onDeleteClicked);
230+
actionLayout->addWidget(m_deleteButton);
231+
225232
m_mainLayout->addWidget(m_bubble);
226233
m_mainLayout->addLayout(actionLayout);
227234

@@ -271,6 +278,7 @@ void ChatMessage::messageCompleted(bool completed)
271278
// Normal assistant – show buttons only when the answer is finished.
272279
m_regenButton->setVisible(completed && !haveToolCalls());
273280
m_copyButton->setVisible(completed && !haveToolCalls());
281+
m_deleteButton->setVisible(completed && !haveToolCalls());
274282

275283
renderMarkdown(m_msg.content, completed);
276284
} else if (m_isTool) {
@@ -577,6 +585,11 @@ void ChatMessage::onSaveToDisk(const QString &fileName, const QString &verbatimC
577585
sourceFile.writeFileContents(verbatimCode.toUtf8());
578586
}
579587

588+
void ChatMessage::onDeleteClicked()
589+
{
590+
emit deleteRequested(m_msg);
591+
}
592+
580593
void ChatMessage::updateUI()
581594
{
582595
m_siblingLabel->setText(QString("%1/%2").arg(m_siblingIdx).arg(m_siblingLeafIds.size()));

llamachatmessage.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class ChatMessage : public QWidget
4343
void regenerateRequested(const Message &msg);
4444
void editRequested(const Message &msg);
4545
void siblingChanged(qint64 siblingId);
46+
void deleteRequested(const Message &msg);
4647

4748
private slots:
4849
void onCopyClicked();
@@ -52,6 +53,7 @@ private slots:
5253
void onNextSiblingClicked();
5354
void onCopyToClipboard(const QString &verbatimCode, const QString &highlightedCode);
5455
void onSaveToDisk(const QString &fileName, const QString &verbatimCode);
56+
void onDeleteClicked();
5557

5658
private:
5759
void buildUI();
@@ -77,6 +79,7 @@ private slots:
7779
QToolButton *m_prevButton{nullptr};
7880
QToolButton *m_nextButton{nullptr};
7981
QToolButton *m_attachedFiles{nullptr};
82+
QToolButton *m_deleteButton{nullptr};
8083
QLabel *m_siblingLabel{nullptr};
8184
MarkdownLabel *m_markdownLabel{nullptr};
8285
QVBoxLayout *m_mainLayout{nullptr};

0 commit comments

Comments
 (0)