ui: added single line reasoning preview (#23601)
* webui: added single line reasoning preview. * patch: reduce width slightly for the previewing section * refactor: move formatter constants to the right file * feat: reimplement reasoning preview with throttled dynamic per-line rendering * chore: fix spacing Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> * chore: refactor to requested changes * refactor: grouped by capture pattern instead of block-level + inline * ui: fax interrupt state only trigger for 1st reasoning message * chore: make reasoning preview respects showThoughtInProgress setting * chore; newline at EOF Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> * fix: thread rawContent so collapsible content can handle compute preview * patch: showThoughtInProgress accidentally blocks rawContent being passed * chore: fix lint * chore: change smoke test --------- Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com>
This commit is contained in:
co-authored by
Aleksander Grygier
parent
0dbfa66a1f
commit
526977068f
@@ -18,6 +18,7 @@ export interface AgenticSection {
|
||||
toolArgs?: string;
|
||||
toolResult?: string;
|
||||
toolResultExtras?: DatabaseMessageExtra[];
|
||||
wasInterrupted?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,7 +52,8 @@ function deriveSingleTurnSections(
|
||||
const isPending = isStreaming && !hasContentAfterReasoning;
|
||||
sections.push({
|
||||
type: isPending ? AgenticSectionType.REASONING_PENDING : AgenticSectionType.REASONING,
|
||||
content: message.reasoningContent
|
||||
content: message.reasoningContent,
|
||||
wasInterrupted: !isStreaming && !hasContentAfterReasoning
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,11 @@ import {
|
||||
SECONDS_PER_MINUTE,
|
||||
SECONDS_PER_HOUR,
|
||||
SHORT_DURATION_THRESHOLD,
|
||||
MEDIUM_DURATION_THRESHOLD
|
||||
MEDIUM_DURATION_THRESHOLD,
|
||||
MAX_PREVIEW_LENGTH,
|
||||
STRIP_MARKDOWN_INLINE_REGEX,
|
||||
STRIP_MARKDOWN_CAPTURE_PATTERNS,
|
||||
NEWLINE_SEPARATOR
|
||||
} from '$lib/constants';
|
||||
|
||||
/**
|
||||
@@ -151,3 +155,33 @@ export function formatAttachmentText(
|
||||
const header = extra ? `${name} (${extra})` : name;
|
||||
return `\n\n--- ${label}: ${header} ---\n${content}`;
|
||||
}
|
||||
|
||||
export function formatReasoningPreview(content: string): { preview: string; overflow: number } {
|
||||
if (!content) return { preview: '', overflow: 0 };
|
||||
|
||||
const lines = content.split(NEWLINE_SEPARATOR);
|
||||
let lastLine = '';
|
||||
|
||||
for (let i = lines.length - 1; i >= 0; i--) {
|
||||
let cleaned = lines[i].trim();
|
||||
if (!cleaned) continue;
|
||||
|
||||
cleaned = cleaned.replace(STRIP_MARKDOWN_INLINE_REGEX, '');
|
||||
for (const [pattern, replacement] of STRIP_MARKDOWN_CAPTURE_PATTERNS) {
|
||||
cleaned = cleaned.replace(pattern, replacement);
|
||||
}
|
||||
|
||||
if (cleaned.length > 0) {
|
||||
lastLine = cleaned;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const fullLength = lastLine.length;
|
||||
const overflow = Math.max(0, fullLength - MAX_PREVIEW_LENGTH);
|
||||
if (fullLength > MAX_PREVIEW_LENGTH) {
|
||||
lastLine = lastLine.slice(0, MAX_PREVIEW_LENGTH) + '...';
|
||||
}
|
||||
|
||||
return { preview: lastLine, overflow };
|
||||
}
|
||||
|
||||
@@ -76,7 +76,8 @@ export {
|
||||
formatJsonPretty,
|
||||
formatTime,
|
||||
formatPerformanceTime,
|
||||
formatAttachmentText
|
||||
formatAttachmentText,
|
||||
formatReasoningPreview
|
||||
} from './formatters';
|
||||
|
||||
// IME utilities
|
||||
|
||||
Reference in New Issue
Block a user