Skip to content

Commit 3f17581

Browse files
committed
fix: inline label only for single reasoning segment
1 parent 5c959c2 commit 3f17581

File tree

4 files changed

+19
-4
lines changed

4 files changed

+19
-4
lines changed

src/components/Messages/MarkdownRenderer.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ interface MarkdownRendererProps {
88
style?: React.CSSProperties;
99
}
1010

11-
export const MarkdownRenderer: React.FC<MarkdownRendererProps> = ({ content, className, style }) => {
11+
export const MarkdownRenderer: React.FC<MarkdownRendererProps> = ({
12+
content,
13+
className,
14+
style,
15+
}) => {
1216
return (
1317
<div className={cn("markdown-content", className)} style={style}>
1418
<MarkdownCore content={content} />

src/components/Messages/ReasoningMessage.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ export const ReasoningMessage: React.FC<ReasoningMessageProps> = ({ message, cla
1818
const isStreaming = message.isStreaming;
1919
const trimmedContent = content?.trim() ?? "";
2020
const hasContent = trimmedContent.length > 0;
21+
const reasoningSegments = message.reasoningSegmentCount ?? 1;
2122
// OpenAI models often emit terse, single-line traces; surface them inline instead of hiding behind the label.
22-
const isSingleLineTrace = !isStreaming && hasContent && !/[\r\n]/.test(trimmedContent);
23+
const isSingleLineTrace =
24+
!isStreaming && hasContent && reasoningSegments === 1 && !/[\r\n]/.test(trimmedContent);
2325
const isCollapsible = !isStreaming && hasContent && !isSingleLineTrace;
2426

2527
// Auto-collapse when streaming ends

src/types/message.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ export interface MuxReasoningPart {
7272
type: "reasoning";
7373
text: string;
7474
timestamp?: number;
75+
segmentCount?: number; // Number of merged reasoning deltas represented by this part
7576
}
7677

7778
// File/Image part type for multimodal messages (matches AI SDK FileUIPart)
@@ -151,6 +152,7 @@ export type DisplayedMessage =
151152
isLastPartOfMessage?: boolean; // True if this is the last part of a multi-part message
152153
timestamp?: number;
153154
tokens?: number; // Reasoning tokens if available
155+
reasoningSegmentCount?: number; // Number of merged reasoning deltas represented by this block
154156
}
155157
| {
156158
type: "stream-error";

src/utils/messages/StreamingMessageAggregator.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,7 @@ export class StreamingMessageAggregator {
608608
type: "reasoning",
609609
text: data.delta,
610610
timestamp: data.timestamp,
611+
segmentCount: 1,
611612
});
612613

613614
// Track delta for token counting and TPS calculation
@@ -793,15 +794,20 @@ export class StreamingMessageAggregator {
793794
timestamp: lastMerged.timestamp ?? part.timestamp,
794795
};
795796
} else if (lastMerged?.type === "reasoning" && part.type === "reasoning") {
796-
// Merge reasoning parts, preserving the first timestamp
797+
// Merge reasoning parts, preserving the first timestamp and accumulating segment count
797798
mergedParts[mergedParts.length - 1] = {
798799
type: "reasoning",
799800
text: lastMerged.text + part.text,
800801
timestamp: lastMerged.timestamp ?? part.timestamp,
802+
segmentCount: (lastMerged.segmentCount ?? 1) + (part.segmentCount ?? 1),
801803
};
802804
} else {
803805
// Different type or tool part - add new part
804-
mergedParts.push(part);
806+
if (part.type === "reasoning") {
807+
mergedParts.push({ ...part, segmentCount: part.segmentCount ?? 1 });
808+
} else {
809+
mergedParts.push(part);
810+
}
805811
}
806812
}
807813

@@ -838,6 +844,7 @@ export class StreamingMessageAggregator {
838844
isPartial: message.metadata?.partial ?? false,
839845
isLastPartOfMessage: isLastPart,
840846
timestamp: part.timestamp ?? baseTimestamp,
847+
reasoningSegmentCount: part.segmentCount ?? 1,
841848
});
842849
} else if (part.type === "text" && part.text) {
843850
// Skip empty text parts

0 commit comments

Comments
 (0)