authorgravatar for 92423096+nateEc@users.noreply.github.comYukun Shan <92423096+nateEc@users.noreply.github.com> 2026-08-15 18:43:50+08:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-08-15 12:43:50+02:00
log1e87029261f9b81061a2a7420849b9eeaf1a2ebe
tree32ed0135c7c965c55539d75d0e6514228336ee02
parent672216d7e152241213a8757892f281e1f4434e8a
signature Signed by PGP key B5690EEEBB952194

fix(web): preserve Claude insight line breaks (#4344)


3 files changed, 18 insertions(+), 0 deletions(-)

apps/web/src/components/chat/MessagesTimeline.logic.test.ts+12
......@@ -5,8 +5,20 @@ import {
55 deriveMessagesTimelineRows,
66 normalizeCompactToolLabel,
77 resolveAssistantMessageCopyState,
8 shouldPreserveAssistantLineBreaks,
89} from "./MessagesTimeline.logic";
910
11describe("shouldPreserveAssistantLineBreaks", () => {
12 it("preserves Claude insight formatting without changing regular markdown", () => {
13 expect(
14 shouldPreserveAssistantLineBreaks(
15 "★ Insight ─────────────────\\nFirst observation\\nSecond observation\\n─────────────────",
16 ),
17 ).toBe(true);
18 expect(shouldPreserveAssistantLineBreaks("A normal\\nmarkdown paragraph")).toBe(false);
19 });
20});
21
1022describe("computeMessageDurationStart", () => {
1123 it("returns message createdAt when there is no preceding user message", () => {
1224 const result = computeMessageDurationStart([
apps/web/src/components/chat/MessagesTimeline.logic.ts+4
......@@ -52,6 +52,10 @@ export function resolveTimelineIsAtEnd(
5252 return contentLength - scroll - scrollLength - endInset <= TIMELINE_FOLLOW_REARM_THRESHOLD_PX;
5353}
5454
55export function shouldPreserveAssistantLineBreaks(text: string): boolean {
56 return /^★ Insight(?:\s|─)/mu.test(text);
57}
58
5559export function resolveTimelineMinimapHeightStyle(itemCount: number): string {
5660 const naturalHeight = Math.max(1, (itemCount - 1) * TIMELINE_MINIMAP_ITEM_SPACING);
5761 return `min(${naturalHeight}px, ${TIMELINE_MINIMAP_MAX_HEIGHT_CSS})`;
apps/web/src/components/chat/MessagesTimeline.tsx+2
......@@ -83,6 +83,7 @@ import {
8383 resolveTimelineMinimapIndexFromPointer,
8484 resolveTimelineMinimapInteractiveWidth,
8585 resolveTimelineMinimapTopPercent,
86 shouldPreserveAssistantLineBreaks,
8687 type StableMessagesTimelineRowsState,
8788 type MessagesTimelineRow,
8889 TIMELINE_MINIMAP_MIN_ITEMS,
......@@ -1113,6 +1114,7 @@ function AssistantTimelineRow({ row }: { row: Extract<TimelineRow, { kind: "mess
11131114 cwd={ctx.markdownCwd}
11141115 threadRef={ctx.threadRef ?? undefined}
11151116 isStreaming={Boolean(row.message.streaming)}
1117 lineBreaks={shouldPreserveAssistantLineBreaks(messageText)}
11161118 skills={ctx.skills}
11171119 />
11181120 <AssistantChangedFilesSection