incognitolm commited on
Commit Β·
55c54a4
1
Parent(s): a2df94b
Message Versions
Browse files- public/css/chat.css +21 -16
- public/js/chat.js +25 -11
public/css/chat.css
CHANGED
|
@@ -99,20 +99,13 @@
|
|
| 99 |
|
| 100 |
/* Version navigator */
|
| 101 |
.msg-version-nav {
|
| 102 |
-
position: absolute;
|
| 103 |
-
bottom: -4px;
|
| 104 |
-
right: 0;
|
| 105 |
display: flex;
|
| 106 |
align-items: center;
|
| 107 |
gap: 4px;
|
| 108 |
font-size: 12px;
|
| 109 |
color: var(--text-muted);
|
| 110 |
-
opacity: 0;
|
| 111 |
-
transition: opacity var(--transition);
|
| 112 |
}
|
| 113 |
|
| 114 |
-
.msg-group:hover .msg-version-nav { opacity: 1; }
|
| 115 |
-
|
| 116 |
.msg-version-nav button {
|
| 117 |
display: flex; align-items: center; justify-content: center;
|
| 118 |
width: 20px; height: 20px; border-radius: 50%;
|
|
@@ -125,22 +118,34 @@
|
|
| 125 |
.msg-actions {
|
| 126 |
display: flex;
|
| 127 |
gap: 3px;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 128 |
opacity: 0;
|
| 129 |
transition: opacity var(--transition);
|
| 130 |
pointer-events: none;
|
| 131 |
-
/* Default: left-aligned (assistant messages) */
|
| 132 |
-
position: absolute;
|
| 133 |
-
bottom: 4px;
|
| 134 |
-
left: 0;
|
| 135 |
}
|
| 136 |
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
|
|
|
|
|
|
| 141 |
}
|
| 142 |
|
| 143 |
-
.msg-group:hover .msg-
|
| 144 |
opacity: 1;
|
| 145 |
pointer-events: auto;
|
| 146 |
}
|
|
|
|
| 99 |
|
| 100 |
/* Version navigator */
|
| 101 |
.msg-version-nav {
|
|
|
|
|
|
|
|
|
|
| 102 |
display: flex;
|
| 103 |
align-items: center;
|
| 104 |
gap: 4px;
|
| 105 |
font-size: 12px;
|
| 106 |
color: var(--text-muted);
|
|
|
|
|
|
|
| 107 |
}
|
| 108 |
|
|
|
|
|
|
|
| 109 |
.msg-version-nav button {
|
| 110 |
display: flex; align-items: center; justify-content: center;
|
| 111 |
width: 20px; height: 20px; border-radius: 50%;
|
|
|
|
| 118 |
.msg-actions {
|
| 119 |
display: flex;
|
| 120 |
gap: 3px;
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
.msg-actions.msg-actions-right {
|
| 124 |
+
justify-content: flex-end;
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
.msg-actions.msg-actions-left {
|
| 128 |
+
justify-content: flex-start;
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
.msg-controls {
|
| 132 |
+
display: flex;
|
| 133 |
+
flex-direction: column;
|
| 134 |
+
gap: 4px;
|
| 135 |
opacity: 0;
|
| 136 |
transition: opacity var(--transition);
|
| 137 |
pointer-events: none;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 138 |
}
|
| 139 |
|
| 140 |
+
.msg-controls.msg-controls-right {
|
| 141 |
+
align-items: flex-end;
|
| 142 |
+
}
|
| 143 |
+
|
| 144 |
+
.msg-controls.msg-controls-left {
|
| 145 |
+
align-items: flex-start;
|
| 146 |
}
|
| 147 |
|
| 148 |
+
.msg-group:hover .msg-controls {
|
| 149 |
opacity: 1;
|
| 150 |
pointer-events: auto;
|
| 151 |
}
|
public/js/chat.js
CHANGED
|
@@ -26,7 +26,19 @@ on('chat:aborted', (msg) => { if (msg.sessionId === activeSessionId) on
|
|
| 26 |
on('chat:error', (msg) => { if (msg.sessionId === activeSessionId) onChatError(msg.error); });
|
| 27 |
on('chat:asset', (msg) => { if (msg.sessionId === activeSessionId) appendAsset(msg.asset); });
|
| 28 |
on('chat:toolCall', (msg) => { if (msg.sessionId === activeSessionId) handleLiveToolCall(msg.call); });
|
| 29 |
-
on('chat:messageEdited', (msg) => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
on('chat:versionSelected', (msg) => { if (msg.sessionId === activeSessionId) renderHistory(msg.history); });
|
| 31 |
|
| 32 |
// Reconnect: reload current session instead of resetting to welcome
|
|
@@ -121,13 +133,14 @@ function appendUserMsg(box, msg, index) {
|
|
| 121 |
|
| 122 |
wrap.appendChild(bubble);
|
| 123 |
|
| 124 |
-
|
| 125 |
-
|
|
|
|
| 126 |
{ icon: 'π', title: 'Copy', fn: () => copyText(text) },
|
| 127 |
{ icon: 'βοΈ', title: 'Edit', fn: () => startUserEdit(wrap, index, msg, text) },
|
| 128 |
], 'right'));
|
| 129 |
-
|
| 130 |
-
|
| 131 |
|
| 132 |
box.appendChild(wrap);
|
| 133 |
}
|
|
@@ -149,13 +162,14 @@ function appendAssistantMsg(box, msg, index) {
|
|
| 149 |
|
| 150 |
wrap.appendChild(bubble);
|
| 151 |
|
| 152 |
-
|
| 153 |
-
|
|
|
|
| 154 |
{ icon: 'π', title: 'Copy', fn: () => copyText(msg.content || '') },
|
| 155 |
{ icon: 'βοΈ', title: 'Edit', fn: () => startAssistantEdit(wrap, index, msg) },
|
| 156 |
], 'left'));
|
| 157 |
-
|
| 158 |
-
|
| 159 |
|
| 160 |
box.appendChild(wrap);
|
| 161 |
}
|
|
@@ -512,8 +526,8 @@ function appendAsset(asset) {
|
|
| 512 |
|
| 513 |
// ββ Submit ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 514 |
|
| 515 |
-
export function submitMessage(text, attachments = []) {
|
| 516 |
-
if (!text.trim() && attachments.length === 0) return;
|
| 517 |
if (isStreaming) { send({ type: 'chat:stop' }); return; }
|
| 518 |
if (!activeSessionId) return;
|
| 519 |
|
|
|
|
| 26 |
on('chat:error', (msg) => { if (msg.sessionId === activeSessionId) onChatError(msg.error); });
|
| 27 |
on('chat:asset', (msg) => { if (msg.sessionId === activeSessionId) appendAsset(msg.asset); });
|
| 28 |
on('chat:toolCall', (msg) => { if (msg.sessionId === activeSessionId) handleLiveToolCall(msg.call); });
|
| 29 |
+
on('chat:messageEdited', (msg) => {
|
| 30 |
+
if (msg.sessionId === activeSessionId) {
|
| 31 |
+
renderHistory(msg.history);
|
| 32 |
+
// Update the session history
|
| 33 |
+
const s = sessions.find(s => s.id === msg.sessionId);
|
| 34 |
+
if (s) s.history = msg.history;
|
| 35 |
+
// If edited message is user, regenerate the response
|
| 36 |
+
const editedMsg = msg.history[msg.messageIndex];
|
| 37 |
+
if (editedMsg && editedMsg.role === 'user') {
|
| 38 |
+
submitMessage('', [], true);
|
| 39 |
+
}
|
| 40 |
+
}
|
| 41 |
+
});
|
| 42 |
on('chat:versionSelected', (msg) => { if (msg.sessionId === activeSessionId) renderHistory(msg.history); });
|
| 43 |
|
| 44 |
// Reconnect: reload current session instead of resetting to welcome
|
|
|
|
| 133 |
|
| 134 |
wrap.appendChild(bubble);
|
| 135 |
|
| 136 |
+
const controls = document.createElement('div');
|
| 137 |
+
controls.className = 'msg-controls msg-controls-right';
|
| 138 |
+
controls.appendChild(buildActions([
|
| 139 |
{ icon: 'π', title: 'Copy', fn: () => copyText(text) },
|
| 140 |
{ icon: 'βοΈ', title: 'Edit', fn: () => startUserEdit(wrap, index, msg, text) },
|
| 141 |
], 'right'));
|
| 142 |
+
if (msg.versions?.length > 1) controls.appendChild(buildVersionNav(msg, index));
|
| 143 |
+
wrap.appendChild(controls);
|
| 144 |
|
| 145 |
box.appendChild(wrap);
|
| 146 |
}
|
|
|
|
| 162 |
|
| 163 |
wrap.appendChild(bubble);
|
| 164 |
|
| 165 |
+
const controls = document.createElement('div');
|
| 166 |
+
controls.className = 'msg-controls msg-controls-left';
|
| 167 |
+
controls.appendChild(buildActions([
|
| 168 |
{ icon: 'π', title: 'Copy', fn: () => copyText(msg.content || '') },
|
| 169 |
{ icon: 'βοΈ', title: 'Edit', fn: () => startAssistantEdit(wrap, index, msg) },
|
| 170 |
], 'left'));
|
| 171 |
+
if (msg.versions?.length > 1) controls.appendChild(buildVersionNav(msg, index));
|
| 172 |
+
wrap.appendChild(controls);
|
| 173 |
|
| 174 |
box.appendChild(wrap);
|
| 175 |
}
|
|
|
|
| 526 |
|
| 527 |
// ββ Submit ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 528 |
|
| 529 |
+
export function submitMessage(text, attachments = [], regenerate = false) {
|
| 530 |
+
if (!text.trim() && attachments.length === 0 && !regenerate) return;
|
| 531 |
if (isStreaming) { send({ type: 'chat:stop' }); return; }
|
| 532 |
if (!activeSessionId) return;
|
| 533 |
|