refactor: Refine Chat Message Processing State Display
This commit is contained in:
parent
6047da3f72
commit
aa4fb786a2
|
|
@ -17,10 +17,16 @@
|
||||||
interface Props {
|
interface Props {
|
||||||
class?: string;
|
class?: string;
|
||||||
message: DatabaseMessage;
|
message: DatabaseMessage;
|
||||||
|
isLastAssistantMessage?: boolean;
|
||||||
siblingInfo?: ChatMessageSiblingInfo | null;
|
siblingInfo?: ChatMessageSiblingInfo | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { class: className = '', message, siblingInfo = null }: Props = $props();
|
let {
|
||||||
|
class: className = '',
|
||||||
|
message,
|
||||||
|
isLastAssistantMessage = false,
|
||||||
|
siblingInfo = null
|
||||||
|
}: Props = $props();
|
||||||
|
|
||||||
const chatActions = getChatActionsContext();
|
const chatActions = getChatActionsContext();
|
||||||
|
|
||||||
|
|
@ -278,6 +284,7 @@
|
||||||
bind:textareaElement
|
bind:textareaElement
|
||||||
class={className}
|
class={className}
|
||||||
{deletionInfo}
|
{deletionInfo}
|
||||||
|
{isLastAssistantMessage}
|
||||||
{message}
|
{message}
|
||||||
messageContent={message.content}
|
messageContent={message.content}
|
||||||
onConfirmDelete={handleConfirmDelete}
|
onConfirmDelete={handleConfirmDelete}
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@
|
||||||
{:else if section.type === AgenticSectionType.TOOL_CALL_STREAMING}
|
{:else if section.type === AgenticSectionType.TOOL_CALL_STREAMING}
|
||||||
{@const streamingIcon = isStreaming ? Loader2 : AlertTriangle}
|
{@const streamingIcon = isStreaming ? Loader2 : AlertTriangle}
|
||||||
{@const streamingIconClass = isStreaming ? 'h-4 w-4 animate-spin' : 'h-4 w-4 text-yellow-500'}
|
{@const streamingIconClass = isStreaming ? 'h-4 w-4 animate-spin' : 'h-4 w-4 text-yellow-500'}
|
||||||
{@const streamingSubtitle = isStreaming ? 'streaming...' : 'incomplete'}
|
{@const streamingSubtitle = isStreaming ? '' : 'incomplete'}
|
||||||
|
|
||||||
<CollapsibleContentBlock
|
<CollapsibleContentBlock
|
||||||
open={isExpanded(index, section)}
|
open={isExpanded(index, section)}
|
||||||
|
|
@ -171,7 +171,7 @@
|
||||||
</CollapsibleContentBlock>
|
</CollapsibleContentBlock>
|
||||||
{:else if section.type === AgenticSectionType.REASONING_PENDING}
|
{:else if section.type === AgenticSectionType.REASONING_PENDING}
|
||||||
{@const reasoningTitle = isStreaming ? 'Reasoning...' : 'Reasoning'}
|
{@const reasoningTitle = isStreaming ? 'Reasoning...' : 'Reasoning'}
|
||||||
{@const reasoningSubtitle = isStreaming ? 'streaming...' : 'incomplete'}
|
{@const reasoningSubtitle = isStreaming ? '' : 'incomplete'}
|
||||||
|
|
||||||
<CollapsibleContentBlock
|
<CollapsibleContentBlock
|
||||||
open={isExpanded(index, section)}
|
open={isExpanded(index, section)}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
assistantMessages: number;
|
assistantMessages: number;
|
||||||
messageTypes: string[];
|
messageTypes: string[];
|
||||||
} | null;
|
} | null;
|
||||||
|
isLastAssistantMessage?: boolean;
|
||||||
message: DatabaseMessage;
|
message: DatabaseMessage;
|
||||||
messageContent: string | undefined;
|
messageContent: string | undefined;
|
||||||
onCopy: () => void;
|
onCopy: () => void;
|
||||||
|
|
@ -51,6 +52,7 @@
|
||||||
let {
|
let {
|
||||||
class: className = '',
|
class: className = '',
|
||||||
deletionInfo,
|
deletionInfo,
|
||||||
|
isLastAssistantMessage = false,
|
||||||
message,
|
message,
|
||||||
messageContent,
|
messageContent,
|
||||||
onConfirmDelete,
|
onConfirmDelete,
|
||||||
|
|
@ -100,6 +102,25 @@
|
||||||
|
|
||||||
let displayedModel = $derived(message.model ?? null);
|
let displayedModel = $derived(message.model ?? null);
|
||||||
|
|
||||||
|
let isCurrentlyLoading = $derived(isLoading());
|
||||||
|
let isStreaming = $derived(isChatStreaming());
|
||||||
|
let hasNoContent = $derived(!message?.content?.trim());
|
||||||
|
let isActivelyProcessing = $derived(isCurrentlyLoading || isStreaming);
|
||||||
|
|
||||||
|
let showProcessingInfoTop = $derived(
|
||||||
|
message?.role === MessageRole.ASSISTANT &&
|
||||||
|
isActivelyProcessing &&
|
||||||
|
hasNoContent &&
|
||||||
|
isLastAssistantMessage
|
||||||
|
);
|
||||||
|
|
||||||
|
let showProcessingInfoBottom = $derived(
|
||||||
|
message?.role === MessageRole.ASSISTANT &&
|
||||||
|
isActivelyProcessing &&
|
||||||
|
!hasNoContent &&
|
||||||
|
isLastAssistantMessage
|
||||||
|
);
|
||||||
|
|
||||||
function handleCopyModel() {
|
function handleCopyModel() {
|
||||||
void copyToClipboard(displayedModel ?? '');
|
void copyToClipboard(displayedModel ?? '');
|
||||||
}
|
}
|
||||||
|
|
@ -111,7 +132,7 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (isLoading() && !message?.content?.trim()) {
|
if (showProcessingInfoTop || showProcessingInfoBottom) {
|
||||||
processingState.startMonitoring();
|
processingState.startMonitoring();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -122,11 +143,13 @@
|
||||||
role="group"
|
role="group"
|
||||||
aria-label="Assistant message with actions"
|
aria-label="Assistant message with actions"
|
||||||
>
|
>
|
||||||
{#if message?.role === MessageRole.ASSISTANT && isLoading() && !message?.content?.trim()}
|
{#if showProcessingInfoTop}
|
||||||
<div class="mt-6 w-full max-w-[48rem]" in:fade>
|
<div class="mt-6 w-full max-w-[48rem]" in:fade>
|
||||||
<div class="processing-container">
|
<div class="processing-container">
|
||||||
<span class="processing-text">
|
<span class="processing-text">
|
||||||
{processingState.getPromptProgressText() ?? processingState.getProcessingMessage()}
|
{processingState.getPromptProgressText() ??
|
||||||
|
processingState.getProcessingMessage() ??
|
||||||
|
'Processing...'}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -193,7 +216,19 @@
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="info my-6 grid gap-4">
|
{#if showProcessingInfoBottom}
|
||||||
|
<div class="mt-4 w-full max-w-[48rem]" in:fade>
|
||||||
|
<div class="processing-container">
|
||||||
|
<span class="processing-text">
|
||||||
|
{processingState.getPromptProgressText() ??
|
||||||
|
processingState.getProcessingMessage() ??
|
||||||
|
'Processing...'}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<div class="info my-6 grid gap-4 tabular-nums">
|
||||||
{#if displayedModel}
|
{#if displayedModel}
|
||||||
<div class="inline-flex flex-wrap items-start gap-2 text-xs text-muted-foreground">
|
<div class="inline-flex flex-wrap items-start gap-2 text-xs text-muted-foreground">
|
||||||
{#if isRouter}
|
{#if isRouter}
|
||||||
|
|
|
||||||
|
|
@ -100,16 +100,26 @@
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter out system messages if showSystemMessage is false
|
|
||||||
const filteredMessages = currentConfig.showSystemMessage
|
const filteredMessages = currentConfig.showSystemMessage
|
||||||
? messages
|
? messages
|
||||||
: messages.filter((msg) => msg.type !== MessageRole.SYSTEM);
|
: messages.filter((msg) => msg.type !== MessageRole.SYSTEM);
|
||||||
|
|
||||||
return filteredMessages.map((message) => {
|
let lastAssistantIndex = -1;
|
||||||
|
for (let i = filteredMessages.length - 1; i >= 0; i--) {
|
||||||
|
if (filteredMessages[i].role === MessageRole.ASSISTANT) {
|
||||||
|
lastAssistantIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filteredMessages.map((message, index) => {
|
||||||
const siblingInfo = getMessageSiblings(allConversationMessages, message.id);
|
const siblingInfo = getMessageSiblings(allConversationMessages, message.id);
|
||||||
|
const isLastAssistantMessage =
|
||||||
|
message.role === MessageRole.ASSISTANT && index === lastAssistantIndex;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
message,
|
message,
|
||||||
|
isLastAssistantMessage,
|
||||||
siblingInfo: siblingInfo || {
|
siblingInfo: siblingInfo || {
|
||||||
message,
|
message,
|
||||||
siblingIds: [message.id],
|
siblingIds: [message.id],
|
||||||
|
|
@ -122,7 +132,12 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex h-full flex-col space-y-10 pt-16 md:pt-24 {className}" style="height: auto; ">
|
<div class="flex h-full flex-col space-y-10 pt-16 md:pt-24 {className}" style="height: auto; ">
|
||||||
{#each displayMessages as { message, siblingInfo } (message.id)}
|
{#each displayMessages as { message, isLastAssistantMessage, siblingInfo } (message.id)}
|
||||||
<ChatMessage class="mx-auto w-full max-w-[48rem]" {message} {siblingInfo} />
|
<ChatMessage
|
||||||
|
class="mx-auto w-full max-w-[48rem]"
|
||||||
|
{message}
|
||||||
|
{isLastAssistantMessage}
|
||||||
|
{siblingInfo}
|
||||||
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
let isCurrentConversationLoading = $derived(isLoading());
|
let isCurrentConversationLoading = $derived(isLoading());
|
||||||
let isStreaming = $derived(isChatStreaming());
|
let isStreaming = $derived(isChatStreaming());
|
||||||
let hasProcessingData = $derived(processingState.processingState !== null);
|
let hasProcessingData = $derived(processingState.processingState !== null);
|
||||||
let processingDetails = $derived(processingState.getProcessingDetails());
|
let processingDetails = $derived(processingState.getTechnicalDetails());
|
||||||
|
|
||||||
let showProcessingInfo = $derived(
|
let showProcessingInfo = $derived(
|
||||||
isCurrentConversationLoading || isStreaming || config().keepStatsVisible || hasProcessingData
|
isCurrentConversationLoading || isStreaming || config().keepStatsVisible || hasProcessingData
|
||||||
|
|
|
||||||
|
|
@ -197,11 +197,7 @@ export function useProcessingState(): UseProcessingStateReturn {
|
||||||
const details: string[] = [];
|
const details: string[] = [];
|
||||||
|
|
||||||
// Always show context info when we have valid data
|
// Always show context info when we have valid data
|
||||||
if (
|
if (stateToUse.contextUsed >= 0 && stateToUse.contextTotal > 0) {
|
||||||
typeof stateToUse.contextTotal === 'number' &&
|
|
||||||
stateToUse.contextUsed >= 0 &&
|
|
||||||
stateToUse.contextTotal > 0
|
|
||||||
) {
|
|
||||||
const contextPercent = Math.round((stateToUse.contextUsed / stateToUse.contextTotal) * 100);
|
const contextPercent = Math.round((stateToUse.contextUsed / stateToUse.contextTotal) * 100);
|
||||||
|
|
||||||
details.push(
|
details.push(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue