// Copyright (C) 2026 Danilo M. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as // published by the Free Software Foundation. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. import QtQuick import ".." // One turn: the question, then the reply with its thinking line, the tool // chips, and an error or stopped mark. Both texts go through Segments, so // the question renders as markdown too. Column { id: msg required property int index required property string user required property string reply required property string think required property string tools required property string error required property bool live required property bool stopped required property bool expanded required property var model // the row, for setting expanded property string running: "" // the tool running now, if any spacing: 6 Rectangle { width: msg.width height: question.height + 16 radius: 8 color: Qt.alpha(Theme.surface, 0.7) Segments { id: question anchors { left: parent.left; right: parent.right; top: parent.top; margins: 8 } text: msg.user } } // Collapsed by default; a click shows the reasoning as plain text. Text { visible: msg.think !== "" text: (msg.expanded ? "▾ " : "▸ ") + (msg.live && msg.reply === "" ? "thinking…" : "thinking") color: Theme.overlay font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4 } MouseArea { anchors.fill: parent cursorShape: Qt.PointingHandCursor onClicked: msg.model.expanded = !msg.expanded } } Text { width: msg.width visible: msg.expanded && msg.think !== "" text: msg.think textFormat: Text.PlainText wrapMode: Text.Wrap color: Theme.subtext font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4 } } Flow { width: msg.width spacing: 6 visible: msg.tools !== "" Repeater { model: msg.tools ? msg.tools.split(",") : [] Rectangle { required property string modelData readonly property bool on: msg.live && msg.running === modelData width: chip.implicitWidth + 14 height: chip.implicitHeight + 6 radius: height / 2 color: Qt.alpha(Theme.surface, 0.9) opacity: on ? 1 : 0.55 Text { id: chip anchors.centerIn: parent text: parent.modelData color: parent.on ? Theme.text : Theme.subtext font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 5 } } } } } Segments { width: msg.width text: msg.reply visible: msg.reply !== "" } Text { visible: msg.error !== "" || msg.stopped width: msg.width text: msg.error !== "" ? msg.error : "stopped" color: msg.error !== "" ? Theme.red : Theme.overlay wrapMode: Text.Wrap font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4 } } }