attachments, errors
frdel committed
Jan 21, 2026 at 12:02 UTC
e53db344b756da6f86e4f4953aee15d739a04a91
4 files changed
+47
-58
webui/components/messages/process-group/process-group.css
+4
-3
@@ -210,7 +210,7 @@
210
211
/* ERR - error type (red) */
212
.status-err {
213
- --step-accent: var(--color-accent);
213
+ --step-accent: var(--color-error-text);
214
color: var(--step-accent);
215
}
216
@@ -250,7 +250,8 @@
250
display: flex;
251
align-items: center;
252
gap: var(--spacing-sm);
253
- margin-left: auto;
253
+ /* margin-left: auto; */
254
+ margin-left: 2em;
255
font-size: 0.65rem;
256
font-family: var(--font-family-code);
257
color: var(--color-text);
@@ -742,7 +743,7 @@
743
}
744
745
.light-mode .status-err {
745
- --step-accent: var(--color-accent);
746
+ --step-accent: var(--color-error-text);
747
color: var(--step-accent);
748
}
749
webui/css/messages.css
+12
-18
@@ -74,8 +74,16 @@
74
.message-user {
75
text-align: end;
76
margin-bottom: var(--spacing-md);
77
+
78
+}
79
+
80
+.message-user .message-text {
81
+ display: inline-block;
82
+ padding: var(--spacing-sm);
83
border: 1px solid var(--color-border);
84
border-radius: var(--border-radius);
85
+ max-width: 80%;
86
+ width: auto;
87
}
88
89
.message-user > div {
@@ -338,8 +346,7 @@
346
flex: 0 0 auto;
347
font-size: var(--font-size-medium);
348
font-weight: 600;
341
- color: var(--color-accent);
342
- opacity: 0.95;
349
+ color: var(--color-error-text);
350
}
351
352
/* Error subtitle (short description) */
@@ -383,7 +390,7 @@
390
.error-content-inner {
391
padding: var(--spacing-md);
392
border-radius: 8px;
386
- border: 1px solid var(--color-accent);
393
+ /* border: 1px solid var(--color-error-text); */
394
margin-left: var(--spacing-md);
395
}
396
@@ -395,12 +402,11 @@
402
font-family: var(--font-family-code);
403
font-size: 0.72rem;
404
line-height: 1.5;
398
- color: var(--color-accent);
399
- opacity: 0.9;
405
+ color: var(--color-error-text);
406
max-height: 30vh;
407
overflow-y: auto;
408
scrollbar-width: thin;
403
- scrollbar-color: var(--color-accent) transparent;
409
+ scrollbar-color: var(--color-error-text) transparent;
410
}
411
412
@@ -622,18 +628,6 @@
628
border-bottom: none;
629
}
630
625
-/* Light mode error group */
626
-.light-mode .error-group-header .expand-icon {
627
- border-color: transparent transparent transparent var(--color-accent);
628
-}
629
-
630
-.light-mode .error-group-header .error-title {
631
- color: var(--color-accent);
632
-}
633
-
634
-.light-mode .error-content-inner {
635
- border: 1px solid var(--color-accent);
636
-}
631
632
.light-mode .message-user {
633
color: #4e4e4e;
webui/index.css
+15
-28
@@ -23,6 +23,7 @@
23
--color-input-dark: #131313;
24
--color-input-focus-dark: #101010;
25
--color-chat-background-dark: #212121;
26
+ --color-error-text-dark:#e72323;
27
28
/* Light mode */
29
--color-background-light: #fafafa;
@@ -39,6 +40,8 @@
40
--color-input-light: #e4e4e4;
41
--color-input-focus-light: #dadada;
42
--color-chat-background-light: #fafafaf3;
43
+ --color-error-text-light:#920000;
44
+
45
46
/* Default to dark mode */
47
--color-background: var(--color-background-dark);
@@ -56,6 +59,7 @@
59
--color-input-focus: var(--color-input-focus-dark);
60
--color-background-hover: color-mix(in srgb, var(--color-border) 50%, transparent);
61
--color-chat-background: var(--color-chat-background-dark);
62
+ --color-error-text:var(--color-error-text-dark);
63
64
/* Spacing variables */
65
--spacing-xxs: 0.15rem;
@@ -98,6 +102,7 @@
102
--color-input-focus: var(--color-input-focus-light);
103
--color-background-hover: color-mix(in srgb, var(--color-border) 50%, transparent);
104
--color-chat-background: var(--color-chat-background-light);
105
+ --color-error-text:var(--color-error-text-light);
106
}
107
108
@@ -457,24 +462,20 @@ h4 {
462
margin-bottom: 10px;
463
padding: var(--spacing-sm);
464
transition: all 0.3s ease;
460
- background-color: var(--color-input);
465
border-radius: 8px;
466
margin-bottom: var(--spacing-xs);
467
max-height: 10em;
468
overflow-y: auto;
469
}
470
467
-.light-mode .preview-section {
468
- background-color: none;
469
-}
471
472
.preview-item {
473
position: relative;
474
width: 120px;
475
height: 120px;
475
- background-color: var(--color-background);
476
- border: 2px solid var(--color-border);
477
- border-radius: 12px;
476
+ /* background-color: var(--color-background); */
477
+ border: 1px solid var(--color-border);
478
+ border-radius: var(--border-radius);
479
display: flex;
480
align-items: center;
481
justify-content: center;
@@ -668,9 +669,8 @@ h4 {
669
position: relative;
670
width: 120px;
671
height: 120px;
671
- background-color: var(--color-background);
672
- border: 2px solid var(--color-border);
673
- border-radius: 12px;
672
+ /* background-color: var(--color-background); */
673
+ border: 1px solid var(--color-border);
674
display: flex;
675
align-items: center;
676
justify-content: center;
@@ -678,11 +678,7 @@ h4 {
678
cursor: pointer;
679
transition: all 0.3s ease;
680
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
681
-}
682
-
683
-.light-mode .attachment-item {
684
- background-color: var(--color-panel-light);
685
- border: 2px solid var(--color-border-light);
681
+ border-radius: var(--border-radius);
682
}
683
684
.attachment-item:hover {
@@ -705,10 +701,11 @@ h4 {
701
height: 100%;
702
object-fit: cover;
703
border-radius: 10px;
708
- background: repeating-linear-gradient(45deg, #fff 0 10px, #e0e0e0 10px 20px);
704
+ background: repeating-linear-gradient(45deg, var(--color-panel) 0 10px, var(--color-chat-background) 10px 20px);
705
706
}
707
708
+
709
/* File attachment styling */
710
.attachment-item.file-type {
711
flex-direction: column;
@@ -738,22 +735,13 @@ h4 {
735
margin-bottom: 4px;
736
}
737
741
-.attachment-preview {
742
- width: 100%;
743
- height: 100%;
744
- object-fit: cover;
745
- border-radius: 10px;
746
- background: repeating-linear-gradient(45deg, #fff 0 10px, #e0e0e0 10px 20px);
747
-
748
-}
749
-
738
/* Chat-history attachments overrides (flat styling) */
739
740
#chat-history .attachments-container {
741
padding: 0 !important;
742
}
743
756
-#chat-history .attachment-item {
744
+/* #chat-history .attachment-item {
745
padding: 0 !important;
746
background-color: transparent !important;
747
border: none !important;
@@ -775,7 +763,7 @@ h4 {
763
764
.attachment-image .attachment-preview {
765
margin-right: 0;
778
-}
766
+} */
767
768
.attachment-info,
769
.file-info {
@@ -821,7 +809,6 @@ h4 {
809
gap: 8px;
810
margin-bottom: 10px;
811
padding: var(--spacing-xs);
824
- background-color: var(--color-border);
812
}
813
814
.preview-item {
webui/js/messages.js
+16
-9
@@ -87,9 +87,9 @@ function updateBadgeText(badge, newCode) {
87
}
88
89
// Process types that should be grouped into collapsible sections
90
-const PROCESS_TYPES = ['agent', 'tool', 'code_exe', 'browser', 'progress', 'info', 'hint', 'util', 'warning'];
90
+const PROCESS_TYPES = ['agent', 'tool', 'code_exe', 'browser', 'progress', 'hint', 'util', 'warning', 'rate_limit'];
91
// Main types that should always be visible (not collapsed)
92
-const MAIN_TYPES = ['user', 'response', 'error', 'rate_limit'];
92
+const MAIN_TYPES = ['user', 'response', 'error', 'info'];
93
94
/**
95
* Helper to append a message container to the correct group in chat history
@@ -319,6 +319,7 @@ export function _drawMessage(
319
let processedContent = content;
320
processedContent = convertImageTags(processedContent);
321
processedContent = convertImgFilePaths(processedContent);
322
+ processedContent = convertFilePaths(processedContent);
323
processedContent = marked.parse(processedContent, { breaks: true });
324
processedContent = convertPathsToLinks(processedContent);
325
processedContent = addBlankTargetsToLinks(processedContent);
@@ -335,7 +336,7 @@ export function _drawMessage(
336
}
337
338
// Ensure action buttons exist
338
- addActionButtonsToElement(bodyDiv);
339
+ // addActionButtonsToElement(bodyDiv);
340
adjustMarkdownRender(contentDiv);
341
342
} else {
@@ -360,7 +361,7 @@ export function _drawMessage(
361
spanElement.innerHTML = convertHTML(content);
362
363
// Ensure action buttons exist
363
- addActionButtonsToElement(bodyDiv);
364
+ // addActionButtonsToElement(bodyDiv);
365
366
}
367
} else {
@@ -549,7 +550,7 @@ export function drawMessageUser(
550
textDiv.appendChild(spanElement);
551
}
552
spanElement.innerHTML = escapeHTML(content);
552
- addActionButtonsToElement(textDiv);
553
+ // addActionButtonsToElement(textDiv);
554
} else {
555
if (textDiv) textDiv.remove();
556
}
@@ -905,7 +906,7 @@ export function drawMessageError(
906
contentInner.appendChild(pre);
907
908
// Add action buttons for copy functionality
908
- addActionButtonsToElement(contentInner);
909
+ // addActionButtonsToElement(contentInner);
910
}
911
912
messageContainer.classList.add("center-container");
@@ -941,7 +942,7 @@ function drawKvps(container, kvps, latex) {
942
addValue(value);
943
}
944
944
- addActionButtonsToElement(tdiv);
945
+ // addActionButtonsToElement(tdiv);
946
947
// autoscroll the KVP value if needed
948
// if (getAutoScroll()) #TODO needs a better redraw system
@@ -1044,7 +1045,7 @@ function drawKvpsIncremental(container, kvps, latex) {
1045
// Clear and rebuild content (for now - could be optimized further)
1046
tdiv.innerHTML = "";
1047
1047
- addActionButtonsToElement(tdiv);
1048
+ // addActionButtonsToElement(tdiv);
1049
1050
if (Array.isArray(value)) {
1051
for (const item of value) {
@@ -1165,6 +1166,10 @@ function convertImgFilePaths(str) {
1166
return str.replace(/img:\/\//g, "/image_get?path=");
1167
}
1168
1169
+function convertFilePaths(str) {
1170
+ return str.replace(/file:\/\//g, "/download_work_dir_file?path=");
1171
+}
1172
+
1173
export function convertIcons(str) {
1174
return str.replace(
1175
/icon:\/\/([a-zA-Z0-9_]+)/g,
@@ -1696,6 +1701,7 @@ function renderStepDetailContent(container, content, kvps, type = null) {
1701
let processedContent = content;
1702
processedContent = convertImageTags(processedContent);
1703
processedContent = convertImgFilePaths(processedContent);
1704
+ processedContent = convertFilePaths(processedContent);
1705
processedContent = marked.parse(processedContent, { breaks: true });
1706
processedContent = convertPathsToLinks(processedContent);
1707
processedContent = addBlankTargetsToLinks(processedContent);
@@ -2115,7 +2121,8 @@ function markProcessGroupComplete(group, responseTitle) {
2121
// Update status badge to END
2122
const statusEl = group.querySelector(".group-status");
2123
if (statusEl) {
2118
- statusEl.innerHTML = '<span class="badge-icon material-symbols-outlined">check</span>END';
2124
+ // statusEl.innerHTML = '<span class="badge-icon material-symbols-outlined">check</span>END';
2125
+ statusEl.innerHTML = 'END';
2126
statusEl.className = "status-badge status-end group-status";
2127
}
2128