Skip to content

Commit 6a13401

Browse files
committed
Small tweaks to thinking
1 parent bb73bb2 commit 6a13401

File tree

4 files changed

+272
-125
lines changed

4 files changed

+272
-125
lines changed

web/src/app/chat/message/AgenticMessage.tsx

+11-6
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import { LlmDescriptor } from "@/lib/hooks";
4343
import { ContinueGenerating } from "./ContinueMessage";
4444
import { MemoizedAnchor, MemoizedParagraph } from "./MemoizedTextComponents";
4545
import { extractCodeText, preprocessLaTeX } from "./codeUtils";
46-
import { ThinkingBox } from "./ThinkingBox";
46+
import { ThinkingBox } from "./thinkingBox/ThinkingBox";
4747
import {
4848
hasCompletedThinkingTokens,
4949
hasPartialThinkingTokens,
@@ -147,7 +147,10 @@ export const AgenticMessage = ({
147147
let processed = incoming;
148148

149149
// Apply thinking tokens processing first
150-
if (hasCompletedThinkingTokens(processed) || hasPartialThinkingTokens(processed)) {
150+
if (
151+
hasCompletedThinkingTokens(processed) ||
152+
hasPartialThinkingTokens(processed)
153+
) {
151154
processed = removeThinkingTokens(processed) as string;
152155
}
153156

@@ -190,7 +193,9 @@ export const AgenticMessage = ({
190193

191194
// Check if content contains thinking tokens
192195
const hasThinkingTokens = useMemo(() => {
193-
return hasCompletedThinkingTokens(content) || hasPartialThinkingTokens(content);
196+
return (
197+
hasCompletedThinkingTokens(content) || hasPartialThinkingTokens(content)
198+
);
194199
}, [content]);
195200

196201
// Extract thinking content
@@ -493,9 +498,9 @@ export const AgenticMessage = ({
493498
{/* Render thinking box if thinking tokens exist */}
494499
{hasThinkingTokens && thinkingContent && (
495500
<div className="mb-2 mt-1">
496-
<ThinkingBox
497-
content={thinkingContent}
498-
isComplete={isComplete || false}
501+
<ThinkingBox
502+
content={thinkingContent}
503+
isComplete={isComplete || false}
499504
isStreaming={!isThinkingTokenComplete || !isComplete}
500505
/>
501506
</div>

web/src/app/chat/message/Messages.tsx

+23-15
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ import rehypeKatex from "rehype-katex";
7373
import "katex/dist/katex.min.css";
7474
import { copyAll, handleCopy } from "./copyingUtils";
7575
import { transformLinkUri } from "@/lib/utils";
76-
import { ThinkingBox } from "./ThinkingBox";
76+
import { ThinkingBox } from "./thinkingBox/ThinkingBox";
7777
import {
7878
hasCompletedThinkingTokens,
7979
hasPartialThinkingTokens,
@@ -278,7 +278,9 @@ export const AIMessage = ({
278278

279279
// Check if content contains thinking tokens (complete or partial)
280280
const hasThinkingTokens = useMemo(() => {
281-
return hasCompletedThinkingTokens(content) || hasPartialThinkingTokens(content);
281+
return (
282+
hasCompletedThinkingTokens(content) || hasPartialThinkingTokens(content)
283+
);
282284
}, [content]);
283285

284286
// Extract thinking content
@@ -302,19 +304,19 @@ export const AIMessage = ({
302304
// or there are no thinking tokens to begin with
303305
const shouldShowContent = useMemo(() => {
304306
if (!hasThinkingTokens) return true;
305-
307+
306308
// If the message is complete, we always show the content
307309
if (isComplete) return true;
308-
310+
309311
// If thinking is not complete, we don't show the content yet
310312
if (!isThinkingTokenComplete) return false;
311-
313+
312314
// If thinking is complete but we're not done with the message yet,
313315
// only show the content if there's actually something to show
314-
const cleanedContent = (typeof finalContent === 'string') ?
315-
finalContent.trim() : finalContent;
316-
317-
return !!cleanedContent && cleanedContent !== '';
316+
const cleanedContent =
317+
typeof finalContent === "string" ? finalContent.trim() : finalContent;
318+
319+
return !!cleanedContent && cleanedContent !== "";
318320
}, [hasThinkingTokens, isComplete, isThinkingTokenComplete, finalContent]);
319321

320322
const processContent = (content: string | JSX.Element) => {
@@ -688,10 +690,10 @@ export const AIMessage = ({
688690

689691
{/* Render thinking box if thinking tokens exist */}
690692
{hasThinkingTokens && thinkingContent && (
691-
<div className="mb-2 mt-1">
692-
<ThinkingBox
693-
content={thinkingContent}
694-
isComplete={isComplete || false}
693+
<div className="mb-2">
694+
<ThinkingBox
695+
content={thinkingContent}
696+
isComplete={isComplete || false}
695697
isStreaming={!isThinkingTokenComplete || !isComplete}
696698
/>
697699
</div>
@@ -761,7 +763,10 @@ export const AIMessage = ({
761763
<CustomTooltip showTick line content="Copy">
762764
<CopyButton
763765
copyAllFn={() =>
764-
copyAll(finalContentProcessed as string, markdownRef)
766+
copyAll(
767+
finalContentProcessed as string,
768+
markdownRef
769+
)
765770
}
766771
/>
767772
</CustomTooltip>
@@ -840,7 +845,10 @@ export const AIMessage = ({
840845
<CustomTooltip showTick line content="Copy">
841846
<CopyButton
842847
copyAllFn={() =>
843-
copyAll(finalContentProcessed as string, markdownRef)
848+
copyAll(
849+
finalContentProcessed as string,
850+
markdownRef
851+
)
844852
}
845853
/>
846854
</CustomTooltip>

web/src/app/chat/message/ThinkingBox.css renamed to web/src/app/chat/message/thinkingBox/ThinkingBox.css

+98-33
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
/* ThinkingBox.css */
2+
3+
/* Apply transition to dark mode as well to ensure smooth color changes */
4+
html {
5+
transition:
6+
background-color 0.2s ease-in-out,
7+
color 0.2s ease-in-out;
8+
}
9+
210
:root {
311
--thinking-border-color: rgba(0, 0, 0, 0.1);
412
--thinking-bg-color: transparent;
@@ -22,10 +30,14 @@
2230
.thinking-box {
2331
width: 98%;
2432
max-width: 100%;
25-
margin: 0.75rem 0;
2633
position: relative;
2734
}
2835

36+
/* Simple direct rule to prevent border flash in dark mode */
37+
.dark .thinking-box * {
38+
border-color: rgba(255, 255, 255, 0.1);
39+
}
40+
2941
.thinking-box__container {
3042
border: 1px solid var(--thinking-border-color);
3143
border-radius: 0.75rem;
@@ -55,6 +67,28 @@
5567
border-bottom: none;
5668
}
5769

70+
/* Style for the transitioning state to prevent flashing */
71+
.thinking-box__container--transitioning {
72+
pointer-events: none; /* Prevent interactions during transition */
73+
}
74+
75+
/* Fix for the flashing white border in dark mode */
76+
.dark .thinking-box__container--transitioning {
77+
border-color: rgba(255, 255, 255, 0.1);
78+
}
79+
80+
.dark .thinking-box__container--transitioning .thinking-box__header {
81+
border-bottom-color: rgba(255, 255, 255, 0.1);
82+
}
83+
84+
.dark .thinking-box__container--transitioning .thinking-box__content {
85+
border-top-color: rgba(255, 255, 255, 0.1);
86+
}
87+
88+
.dark .thinking-box__container--transitioning .thinking-box__preview--crawling {
89+
border-top-color: rgba(255, 255, 255, 0.1);
90+
}
91+
5892
.thinking-box__header {
5993
display: flex;
6094
align-items: center;
@@ -95,7 +129,6 @@
95129
.thinking-box__timer {
96130
font-size: 0.8rem;
97131
color: var(--thinking-text-color);
98-
margin-left: 0.25rem;
99132
}
100133

101134
.thinking-box__collapse-icon {
@@ -167,37 +200,37 @@
167200
.thinking-box__fade-container::before {
168201
top: 0;
169202
background: linear-gradient(
170-
to bottom,
171-
var(--thinking-fade-start),
172-
rgba(var(--thinking-fade-start-rgb, 249, 250, 251), 0.85) 25%,
203+
to bottom,
204+
var(--thinking-fade-start),
205+
rgba(var(--thinking-fade-start-rgb, 249, 250, 251), 0.85) 25%,
173206
var(--thinking-fade-end) 100%
174207
);
175208
}
176209

177210
.thinking-box__fade-container::after {
178211
bottom: 0;
179212
background: linear-gradient(
180-
to top,
181-
var(--thinking-fade-start),
182-
rgba(var(--thinking-fade-start-rgb, 249, 250, 251), 0.85) 25%,
213+
to top,
214+
var(--thinking-fade-start),
215+
rgba(var(--thinking-fade-start-rgb, 249, 250, 251), 0.85) 25%,
183216
var(--thinking-fade-end) 100%
184217
);
185218
}
186219

187220
.dark .thinking-box__fade-container::before {
188221
background: linear-gradient(
189-
to bottom,
190-
var(--thinking-fade-start),
191-
rgba(var(--thinking-fade-start-rgb, 30, 41, 59), 0.85) 25%,
222+
to bottom,
223+
var(--thinking-fade-start),
224+
rgba(var(--thinking-fade-start-rgb, 30, 41, 59), 0.85) 25%,
192225
var(--thinking-fade-end) 100%
193226
);
194227
}
195228

196229
.dark .thinking-box__fade-container::after {
197230
background: linear-gradient(
198-
to top,
199-
var(--thinking-fade-start),
200-
rgba(var(--thinking-fade-start-rgb, 30, 41, 59), 0.85) 25%,
231+
to top,
232+
var(--thinking-fade-start),
233+
rgba(var(--thinking-fade-start-rgb, 30, 41, 59), 0.85) 25%,
201234
var(--thinking-fade-end) 100%
202235
);
203236
}
@@ -218,8 +251,20 @@
218251
transform: translateZ(0);
219252
backface-visibility: hidden;
220253
-webkit-font-smoothing: antialiased;
221-
-webkit-mask-image: linear-gradient(to bottom, transparent, black 12%, black 88%, transparent);
222-
mask-image: linear-gradient(to bottom, transparent, black 12%, black 88%, transparent);
254+
-webkit-mask-image: linear-gradient(
255+
to bottom,
256+
transparent,
257+
black 12%,
258+
black 88%,
259+
transparent
260+
);
261+
mask-image: linear-gradient(
262+
to bottom,
263+
transparent,
264+
black 12%,
265+
black 88%,
266+
transparent
267+
);
223268
}
224269

225270
/* Enhanced text during crawling */
@@ -235,25 +280,39 @@
235280

236281
/* Animation for thinking indicator */
237282
@keyframes pulse {
238-
0% { opacity: 0.5; }
239-
50% { opacity: 1; }
240-
100% { opacity: 0.5; }
283+
0% {
284+
opacity: 0.5;
285+
}
286+
50% {
287+
opacity: 1;
288+
}
289+
100% {
290+
opacity: 0.5;
291+
}
241292
}
242293

243294
/* Fade in animation */
244295
@keyframes fadeIn {
245-
from { opacity: 0; }
246-
to { opacity: 1; }
296+
from {
297+
opacity: 0;
298+
}
299+
to {
300+
opacity: 1;
301+
}
247302
}
248303

249304
/* Smooth scrolling effect */
250305
@keyframes scrollText {
251-
0% { transform: translateY(0); }
252-
100% { transform: translateY(-100%); }
306+
0% {
307+
transform: translateY(0);
308+
}
309+
100% {
310+
transform: translateY(-100%);
311+
}
253312
}
254313

255314
.thinking-box__preview-text {
256-
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
315+
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
257316
font-size: 0.7rem;
258317
color: var(--thinking-text-color);
259318
white-space: pre-wrap;
@@ -266,17 +325,23 @@
266325

267326
/* Enhanced masking during crawling */
268327
.thinking-box__preview--crawling .thinking-box__scroll-content {
269-
-webkit-mask-image: linear-gradient(to bottom, transparent, black 8%, black 92%, transparent);
270-
mask-image: linear-gradient(to bottom, transparent, black 8%, black 92%, transparent);
328+
-webkit-mask-image: linear-gradient(
329+
to bottom,
330+
transparent,
331+
black 8%,
332+
black 92%,
333+
transparent
334+
);
335+
mask-image: linear-gradient(
336+
to bottom,
337+
transparent,
338+
black 8%,
339+
black 92%,
340+
transparent
341+
);
271342
padding: 0.75rem 1rem;
272343
}
273344

274-
.thinking-box__icon--active {
275-
animation: pulse 1.5s infinite ease-in-out;
276-
opacity: 1;
277-
color: var(--thinking-title-color);
278-
}
279-
280345
/* Make sure the preview adjusts immediately when new content arrives */
281346
.thinking-box__preview--crawling .thinking-box__scroll-content {
282347
transition: height 0.3s ease-out;
@@ -302,4 +367,4 @@
302367

303368
.dark .thinking-box__container--collapsed .thinking-box__header:hover {
304369
background-color: rgba(255, 255, 255, 0.03);
305-
}
370+
}

0 commit comments

Comments
 (0)