@@ -357,14 +357,90 @@ void ChatEditor::refreshMessages(const QVector<Message> &messages, qint64 leafNo
357357 scrollToBottom ();
358358}
359359
360- void ChatEditor::onMessageAppended (const Message &msg)
360+ void ChatEditor::onMessageAppended (const Message &msg, qint64 pendingId )
361361{
362- Conversation c = ChatManager::instance ().currentConversation ( );
363- ViewingChat chat = ChatManager::instance (). getViewingChat (c. id );
364- refreshMessages (chat.messages , msg.id );
362+ ViewingChat chat = ChatManager::instance ().getViewingChat (msg. convId );
363+ if (pendingId < 0 ) {
364+ refreshMessages (chat.messages , msg.id );
365365
366- m_input->setIsGenerating (false );
366+ m_input->setIsGenerating (false );
367+ scrollToBottom ();
368+ return ;
369+ }
370+
371+ // Delete old server‑props widget if it exists
372+ if (m_propsWidget) {
373+ m_propsWidget->deleteLater ();
374+ m_propsWidget = nullptr ;
375+ }
367376
377+ if (m_followUpWidget) {
378+ m_followUpWidget->deleteLater ();
379+ m_followUpWidget = nullptr ;
380+ }
381+
382+ QMap<qint64, Message> map;
383+ for (const Message &m : chat.messages )
384+ map.insert (m.id , m);
385+
386+ // Skip root / orphan messages
387+ if (msg.type == " root" )
388+ return ;
389+
390+ int siblingIdx = 1 ;
391+ QVector<qint64> siblings;
392+ if (msg.parent >= 0 ) {
393+ const Message *parent = &map[msg.parent ];
394+ for (qint64 cid : parent->children ) {
395+ siblings.append (cid);
396+ if (msg.id == cid)
397+ siblingIdx = siblings.size (); // 1‑based index
398+ }
399+ }
400+
401+ // Find the leaf of each sibling
402+ QVector<qint64> leafs;
403+ for (qint64 cid : siblings) {
404+ const Message *cur = &map[cid];
405+ while (!cur->children .isEmpty ())
406+ cur = &map[cur->children .back ()];
407+ leafs.append (cur->id );
408+ }
409+
410+ ChatMessage *w{nullptr };
411+ auto it = std::find_if (m_messageWidgets.begin (),
412+ m_messageWidgets.end (),
413+ [this , msg, pendingId](ChatMessage *cm) {
414+ return cm->message ().id == (pendingId < 0 ? msg.id : pendingId);
415+ });
416+ if (it == m_messageWidgets.end ()) {
417+ w = new ChatMessage (msg, leafs, siblingIdx, widget ());
418+ connect (w, &ChatMessage::editRequested, this , &ChatEditor::onEditRequested);
419+ connect (w, &ChatMessage::regenerateRequested, this , &ChatEditor::onRegenerateRequested);
420+ connect (w, &ChatMessage::siblingChanged, this , &ChatEditor::onSiblingChanged);
421+
422+ m_messageLayout->addWidget (w);
423+ m_messageWidgets.append (w);
424+
425+ // Speed‑label handling for assistant messages
426+ if (settings ().showTokensPerSecond .value () && !w->isUser ()) {
427+ m_messageLayout->addWidget (m_speedLabel);
428+ m_speedLabel->setVisible (true );
429+ }
430+ } else {
431+ w = *it;
432+ w->message () = msg;
433+
434+ w->setSiblingIdx (siblingIdx);
435+ w->setSiblingLeafIds (siblings);
436+
437+ w->renderMarkdown (msg.content );
438+ w->messageCompleted (true );
439+ }
440+
441+ updateSpeedLabel (msg);
442+
443+ m_input->setIsGenerating (false );
368444 scrollToBottom ();
369445}
370446
@@ -464,13 +540,19 @@ void ChatEditor::onEditingCancelled()
464540
465541void ChatEditor::onRegenerateRequested (const Message &msg)
466542{
543+ Message msgCopy = msg;
467544 ViewingChat chat = ChatManager::instance ().getViewingChat (msg.convId );
468545
469- ChatManager::instance ().replaceMessageAndGenerate (chat.conv .id ,
470- msg.parent ,
546+ // refreshMessages will invalidate msg, which part of a ChatMessage object
547+ refreshMessages (chat.messages , msgCopy.parent );
548+
549+ ChatManager::instance ().replaceMessageAndGenerate (msgCopy.convId ,
550+ msgCopy.parent ,
471551 QString (),
472- msg.extra ,
473- [this ](qint64 leafId) { scrollToBottom (); });
552+ msgCopy.extra ,
553+ [this , msgCopy](qint64 leafId) {
554+ scrollToBottom ();
555+ });
474556
475557 m_userInteracted = false ;
476558}
0 commit comments