import QtQuick import QtQuick.Controls import QtQuick.Layouts // One message in the transcript: the prompt, the answer, or an error. The // answer arrives as plain text while it streams and is rendered from markdown // (by the engine, through AgentCore::renderMarkdown) once it is complete. Rectangle { id: card property string role: "agent" // user | agent | error property string text: "" property string html: "" property bool complete: true radius: Theme.radius color: role === "user" ? Theme.surfaceAlt : Theme.surface border.width: 1 border.color: role === "error" ? Theme.err : role === "user" ? Theme.border : Theme.border implicitHeight: layout.implicitHeight + Theme.pad * 2 ColumnLayout { id: layout anchors { left: parent.left right: parent.right top: parent.top margins: Theme.pad } spacing: Theme.gap RowLayout { spacing: Theme.gap Rectangle { width: 6 height: 6 radius: 3 color: card.role === "user" ? Theme.accent : card.role === "error" ? Theme.err : Theme.ok } Text { text: card.role === "user" ? "You" : card.role === "error" ? "Error" : "CST-agent" color: Theme.textDim font.pixelSize: Theme.smallSize font.bold: true } Text { visible: !card.complete text: "streaming…" color: Theme.textFaint font.pixelSize: Theme.smallSize } Item { Layout.fillWidth: true } ToolButton { implicitWidth: 26 implicitHeight: 22 visible: card.text.length > 0 ToolTip.visible: hovered ToolTip.text: "Copy" contentItem: Text { text: "⧉" color: parent.hovered ? Theme.text : Theme.textFaint font.pixelSize: Theme.smallSize horizontalAlignment: Text.AlignHCenter } background: Rectangle { radius: Theme.radiusSm color: parent.hovered ? Theme.surfaceHi : "transparent" } onClicked: { plain.text = card.text plain.selectAll() plain.copy() } } } // Hidden holder so "copy" always has the plain text, rtf or not. TextEdit { id: plain visible: false } TextEdit { id: streamText visible: card.html.length === 0 Layout.fillWidth: true text: card.text readOnly: true selectByMouse: true wrapMode: TextEdit.Wrap color: card.role === "error" ? Theme.err : Theme.text font.pixelSize: Theme.bodySize selectionColor: Theme.accentDim } Text { visible: card.html.length > 0 Layout.fillWidth: true text: card.html textFormat: Text.RichText color: Theme.text font.pixelSize: Theme.bodySize wrapMode: Text.Wrap onLinkActivated: function (link) { Qt.openUrlExternally(link) } } } }