Skip to content

Commit 45c43a2

Browse files
committed
fix: improve the think block
1 parent 827fed9 commit 45c43a2

File tree

2 files changed

+175
-11
lines changed

2 files changed

+175
-11
lines changed

src/pages/acp/acp.scss

Lines changed: 96 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -689,22 +689,114 @@
689689
&.thought {
690690
align-self: stretch;
691691

692-
.acp-message-content {
692+
.acp-thinking-block {
693693
background: color-mix(
694694
in srgb,
695695
var(--popup-background-color),
696696
var(--secondary-text-color) 2%
697697
);
698-
border: 1px dashed
699-
color-mix(in srgb, var(--border-color), transparent 10%);
698+
border: 1px solid
699+
color-mix(in srgb, var(--border-color), transparent 20%);
700+
border-radius: 12px;
701+
overflow: hidden;
702+
transition: border-color 0.3s ease;
703+
}
704+
705+
&.streaming .acp-thinking-block {
706+
border-color: color-mix(
707+
in srgb,
708+
var(--active-color),
709+
transparent 60%
710+
);
711+
}
712+
713+
.acp-thinking-header {
714+
display: flex;
715+
align-items: center;
716+
justify-content: space-between;
717+
padding: 10px 14px;
718+
cursor: pointer;
719+
user-select: none;
720+
transition: background 0.15s ease;
721+
722+
&:active {
723+
background: color-mix(
724+
in srgb,
725+
var(--secondary-text-color),
726+
transparent 92%
727+
);
728+
}
729+
}
730+
731+
.acp-thinking-header-left {
732+
display: flex;
733+
align-items: center;
734+
gap: 10px;
735+
min-width: 0;
736+
}
737+
738+
.acp-thinking-icon {
739+
font-size: 18px;
740+
color: color-mix(
741+
in srgb,
742+
var(--secondary-text-color),
743+
transparent 40%
744+
);
745+
transition: color 0.3s ease;
746+
flex-shrink: 0;
747+
748+
&.active {
749+
color: var(--active-color);
750+
animation: acp-streaming-pulse 1.5s ease-in-out infinite;
751+
}
752+
}
753+
754+
.acp-thinking-title {
755+
font-size: 0.8rem;
756+
font-weight: 600;
700757
color: color-mix(
701758
in srgb,
702759
var(--secondary-text-color),
703760
transparent 20%
704761
);
705-
border-radius: 12px;
762+
}
763+
764+
.acp-thinking-chevron {
765+
font-size: 18px;
766+
color: color-mix(
767+
in srgb,
768+
var(--secondary-text-color),
769+
transparent 50%
770+
);
771+
transition: transform 0.2s ease;
772+
flex-shrink: 0;
773+
774+
&.expanded {
775+
transform: rotate(180deg);
776+
}
777+
}
778+
779+
.acp-thinking-body {
780+
display: none;
781+
border-top: 1px solid var(--border-color);
782+
background: color-mix(
783+
in srgb,
784+
var(--popup-background-color),
785+
var(--secondary-text-color) 1%
786+
);
706787
padding: 12px 16px;
707788
font-style: italic;
789+
font-size: 0.82rem;
790+
line-height: 1.6;
791+
color: color-mix(
792+
in srgb,
793+
var(--secondary-text-color),
794+
transparent 30%
795+
);
796+
797+
&.expanded {
798+
display: block;
799+
}
708800
}
709801
}
710802

src/pages/acp/components/chatMessage.js

Lines changed: 79 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -280,11 +280,88 @@ async function resolveExistingPath(candidates = []) {
280280
return null;
281281
}
282282

283+
function ThoughtMessage({
284+
message: initMessage,
285+
isResponding: initResponding,
286+
}) {
287+
let message = initMessage;
288+
let messageResponding = initResponding;
289+
let isExpanded = false;
290+
291+
const $icon = <i className="icon react acp-thinking-icon"></i>;
292+
const $title = <span className="acp-thinking-title"></span>;
293+
const $chevron = <i className="icon expand_more acp-thinking-chevron"></i>;
294+
const $body = <div className="acp-thinking-body"></div>;
295+
296+
const $header = (
297+
<div
298+
className="acp-thinking-header"
299+
onclick={() => {
300+
isExpanded = !isExpanded;
301+
$body.classList.toggle("expanded", isExpanded);
302+
$chevron.classList.toggle("expanded", isExpanded);
303+
}}
304+
>
305+
<div className="acp-thinking-header-left">
306+
{$icon}
307+
{$title}
308+
</div>
309+
{$chevron}
310+
</div>
311+
);
312+
313+
function renderThinking() {
314+
$body.innerHTML = "";
315+
const textBlocks = (message.content || []).filter((b) => b.type === "text");
316+
const text = textBlocks.map((b) => b.text).join("\n");
317+
if (text) {
318+
const $markdown = <div className="acp-markdown-block md"></div>;
319+
$markdown.innerHTML = renderMarkdown(text);
320+
$body.append($markdown);
321+
}
322+
323+
const isActive = Boolean(messageResponding);
324+
$title.textContent = isActive ? "Thinking…" : "Thought Process";
325+
$icon.classList.toggle("active", isActive);
326+
$el.classList.toggle("streaming", isActive);
327+
}
328+
329+
renderThinking();
330+
331+
const $el = (
332+
<div className="acp-message thought">
333+
<div className="acp-thinking-block">
334+
{$header}
335+
{$body}
336+
</div>
337+
</div>
338+
);
339+
340+
const timestamp = new Date(message.timestamp);
341+
$el.title = Number.isNaN(timestamp.getTime())
342+
? ""
343+
: timestamp.toLocaleString();
344+
345+
$el.update = (msg) => {
346+
message = msg.message || msg;
347+
if ("isResponding" in msg) messageResponding = Boolean(msg.isResponding);
348+
renderThinking();
349+
const ts = new Date(message.timestamp);
350+
$el.title = Number.isNaN(ts.getTime()) ? "" : ts.toLocaleString();
351+
};
352+
353+
return $el;
354+
}
355+
283356
export default function ChatMessage({
284357
message,
285358
cwd = "",
286359
isResponding = false,
287360
}) {
361+
if (message.role === "thought") {
362+
return ThoughtMessage({ message, isResponding });
363+
}
364+
288365
let messageCwd = cwd;
289366
let messageResponding = isResponding;
290367

@@ -342,7 +419,7 @@ export default function ChatMessage({
342419
};
343420

344421
function appendTextBlock(text) {
345-
if (message.role === "agent" || message.role === "thought") {
422+
if (message.role === "agent") {
346423
const $markdown = <div className="acp-markdown-block md"></div>;
347424
$markdown.innerHTML = renderMarkdown(text);
348425
$content.append($markdown);
@@ -434,12 +511,7 @@ export default function ChatMessage({
434511
</span>,
435512
);
436513
}
437-
$role.textContent =
438-
message.role === "user"
439-
? "You"
440-
: message.role === "thought"
441-
? "Thinking"
442-
: "Agent";
514+
$role.textContent = message.role === "user" ? "You" : "Agent";
443515
$meta.hidden = $meta.childElementCount === 0;
444516
const timestamp = new Date(message.timestamp);
445517
$el.title = Number.isNaN(timestamp.getTime())

0 commit comments

Comments
 (0)