ai: cleaner message block delegate, add regen button

This commit is contained in:
end-4
2025-10-30 00:40:23 +01:00
parent 128808a56d
commit fcc2ee3551
5 changed files with 90 additions and 44 deletions
@@ -105,7 +105,7 @@ Rectangle {
anchors.right: parent.right anchors.right: parent.right
anchors.leftMargin: 10 anchors.leftMargin: 10
anchors.rightMargin: 10 anchors.rightMargin: 10
spacing: 7 spacing: 12
Item { Item {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
@@ -177,6 +177,20 @@ Rectangle {
ButtonGroup { ButtonGroup {
spacing: 5 spacing: 5
AiMessageControlButton {
id: regenButton
buttonIcon: "refresh"
visible: messageData?.role === 'assistant'
onClicked: {
Ai.regenerate(root.messageIndex)
}
StyledToolTip {
text: Translation.tr("Regenerate")
}
}
AiMessageControlButton { AiMessageControlButton {
id: copyButton id: copyButton
buttonIcon: activated ? "inventory" : "content_copy" buttonIcon: activated ? "inventory" : "content_copy"
@@ -254,28 +268,50 @@ Rectangle {
spacing: 0 spacing: 0
Repeater { Repeater {
model: root.messageBlocks.length model: ScriptModel {
delegate: Loader { values: Array.from({ length: root.messageBlocks.length }, (msg, i) => {
required property int index return ({
property var thisBlock: root.messageBlocks[index] type: root.messageBlocks[i].type
Layout.fillWidth: true })
// property var segment: thisBlock });
property var segmentContent: thisBlock.content }
property var segmentLang: thisBlock.lang
property var messageData: root.messageData
property var editing: root.editing
property var renderMarkdown: root.renderMarkdown
property var enableMouseSelection: root.enableMouseSelection
property bool thinking: root.messageData?.thinking ?? true
property bool done: root.messageData?.done ?? false
property bool completed: thisBlock.completed ?? false
property bool forceDisableChunkSplitting: root.messageData.content.includes("```") delegate: DelegateChooser {
id: messageDelegate
source: thisBlock.type === "code" ? "MessageCodeBlock.qml" : role: "type"
thisBlock.type === "think" ? "MessageThinkBlock.qml" :
"MessageTextBlock.qml"
DelegateChoice { roleValue: "code"; MessageCodeBlock {
required property int index
property var thisBlock: root.messageBlocks[index]
editing: root.editing
renderMarkdown: root.renderMarkdown
enableMouseSelection: root.enableMouseSelection
segmentContent: thisBlock.content
segmentLang: thisBlock.lang
messageData: root.messageData
} }
DelegateChoice { roleValue: "think"; MessageThinkBlock {
required property int index
property var thisBlock: root.messageBlocks[index]
editing: root.editing
renderMarkdown: root.renderMarkdown
enableMouseSelection: root.enableMouseSelection
segmentContent: thisBlock.content
messageData: root.messageData
done: root.messageData?.done ?? false
completed: thisBlock.completed ?? false
} }
DelegateChoice { roleValue: "text"; MessageTextBlock {
required property int index
property var thisBlock: root.messageBlocks[index]
editing: root.editing
renderMarkdown: root.renderMarkdown
enableMouseSelection: root.enableMouseSelection
segmentContent: thisBlock.content
messageData: root.messageData
done: root.messageData?.done ?? false
forceDisableChunkSplitting: root.messageData.content.includes("```")
} }
} }
} }
} }
@@ -13,22 +13,20 @@ import org.kde.syntaxhighlighting
ColumnLayout { ColumnLayout {
id: root id: root
// These are needed on the parent loader // These are needed on the parent loader
property bool editing: parent?.editing ?? false property bool editing: false
property bool renderMarkdown: parent?.renderMarkdown ?? true property bool renderMarkdown: true
property bool enableMouseSelection: parent?.enableMouseSelection ?? false property bool enableMouseSelection: false
property var segmentContent: parent?.segmentContent ?? ({}) property var segmentContent: ({})
property var segmentLang: parent?.segmentLang ?? "txt" property var segmentLang: "txt"
property var messageData: {}
property bool isCommandRequest: segmentLang === "command" property bool isCommandRequest: segmentLang === "command"
property var displayLang: (isCommandRequest ? "bash" : segmentLang) property var displayLang: (isCommandRequest ? "bash" : segmentLang)
property var messageData: parent?.messageData ?? {}
property real codeBlockBackgroundRounding: Appearance.rounding.small property real codeBlockBackgroundRounding: Appearance.rounding.small
property real codeBlockHeaderPadding: 3 property real codeBlockHeaderPadding: 3
property real codeBlockComponentSpacing: 2 property real codeBlockComponentSpacing: 2
spacing: codeBlockComponentSpacing spacing: codeBlockComponentSpacing
anchors.left: parent.left
anchors.right: parent.right
Rectangle { // Code background Rectangle { // Code background
Layout.fillWidth: true Layout.fillWidth: true
@@ -14,17 +14,17 @@ import Quickshell.Hyprland
ColumnLayout { ColumnLayout {
id: root id: root
// These are needed on the parent loader // These are needed on the parent loader
property bool editing: parent?.editing ?? false property bool editing: false
property bool renderMarkdown: parent?.renderMarkdown ?? true property bool renderMarkdown: true
property bool enableMouseSelection: parent?.enableMouseSelection ?? false property bool enableMouseSelection: false
property string segmentContent: parent?.segmentContent ?? ({}) property var segmentContent: ({})
property var messageData: parent?.messageData ?? {} property var messageData: {}
property bool done: parent?.done ?? true property bool done: true
property list<string> renderedLatexHashes: [] property bool forceDisableChunkSplitting: false
property list<string> renderedLatexHashes: []
property string renderedSegmentContent: "" property string renderedSegmentContent: ""
property string shownText: "" property string shownText: ""
property bool forceDisableChunkSplitting: parent?.forceDisableChunkSplitting ?? false
property bool fadeChunkSplitting: !forceDisableChunkSplitting && !editing && !/\n\|/.test(shownText) && Config.options.sidebar.ai.textFadeIn property bool fadeChunkSplitting: !forceDisableChunkSplitting && !editing && !/\n\|/.test(shownText) && Config.options.sidebar.ai.textFadeIn
Layout.fillWidth: true Layout.fillWidth: true
@@ -11,13 +11,13 @@ import Qt5Compat.GraphicalEffects
Item { Item {
id: root id: root
// These are needed on the parent loader // These are needed on the parent loader
property bool editing: parent?.editing ?? false property bool editing: false
property bool renderMarkdown: parent?.renderMarkdown ?? true property bool renderMarkdown: true
property bool enableMouseSelection: parent?.enableMouseSelection ?? false property bool enableMouseSelection: false
property string segmentContent: parent?.segmentContent ?? ({}) property var segmentContent: ({})
property var messageData: parent?.messageData ?? {} property var messageData: {}
property bool done: parent?.done ?? true property bool done: true
property bool completed: parent?.completed ?? false property bool completed: false
property real thinkBlockBackgroundRounding: Appearance.rounding.small property real thinkBlockBackgroundRounding: Appearance.rounding.small
property real thinkBlockHeaderPaddingVertical: 3 property real thinkBlockHeaderPaddingVertical: 3
@@ -769,6 +769,18 @@ Singleton {
root.pendingFilePath = CF.FileUtils.trimFileProtocol(filePath); root.pendingFilePath = CF.FileUtils.trimFileProtocol(filePath);
} }
function regenerate(messageIndex) {
if (messageIndex < 0 || messageIndex >= messageIDs.length) return;
const id = root.messageIDs[messageIndex];
const message = root.messageByID[id];
if (message.role !== "assistant") return;
// Remove all messages after this one
for (let i = root.messageIDs.length - 1; i >= messageIndex; i--) {
root.removeMessage(i);
}
requester.makeRequest();
}
function createFunctionOutputMessage(name, output, includeOutputInChat = true) { function createFunctionOutputMessage(name, output, includeOutputInChat = true) {
return aiMessageComponent.createObject(root, { return aiMessageComponent.createObject(root, {
"role": "user", "role": "user",