fix(chat): improve message handling, fix type errors and migrate changes to enhance branch (#50)

This commit is contained in:
Felix
2026-02-11 17:10:53 +08:00
committed by GitHub
Unverified
parent bc7da0085b
commit fcba8b86d5
5 changed files with 395 additions and 66 deletions

View File

@@ -7,13 +7,13 @@
import { useEffect, useRef, useState } from 'react';
import { AlertCircle, Bot, MessageSquare, Sparkles } from 'lucide-react';
import { Card, CardContent } from '@/components/ui/card';
import { useChatStore } from '@/stores/chat';
import { useChatStore, type RawMessage } from '@/stores/chat';
import { useGatewayStore } from '@/stores/gateway';
import { LoadingSpinner } from '@/components/common/LoadingSpinner';
import { ChatMessage } from './ChatMessage';
import { ChatInput } from './ChatInput';
import { ChatToolbar } from './ChatToolbar';
import { extractText } from './message-utils';
import { extractImages, extractText, extractThinking, extractToolUse } from './message-utils';
import { useTranslation } from 'react-i18next';
export function Chat() {
@@ -27,6 +27,7 @@ export function Chat() {
const error = useChatStore((s) => s.error);
const showThinking = useChatStore((s) => s.showThinking);
const streamingMessage = useChatStore((s) => s.streamingMessage);
const streamingTools = useChatStore((s) => s.streamingTools);
const loadHistory = useChatStore((s) => s.loadHistory);
const loadSessions = useChatStore((s) => s.loadSessions);
const sendMessage = useChatStore((s) => s.sendMessage);
@@ -38,10 +39,16 @@ export function Chat() {
// Load data when gateway is running
useEffect(() => {
if (isGatewayRunning) {
loadHistory();
loadSessions();
}
if (!isGatewayRunning) return;
let cancelled = false;
(async () => {
await loadSessions();
if (cancelled) return;
await loadHistory();
})();
return () => {
cancelled = true;
};
}, [isGatewayRunning, loadHistory, loadSessions]);
// Auto-scroll on new messages or streaming
@@ -78,6 +85,14 @@ export function Chat() {
: null;
const streamText = streamMsg ? extractText(streamMsg) : (typeof streamingMessage === 'string' ? streamingMessage : '');
const hasStreamText = streamText.trim().length > 0;
const streamThinking = streamMsg ? extractThinking(streamMsg) : null;
const hasStreamThinking = showThinking && !!streamThinking && streamThinking.trim().length > 0;
const streamTools = streamMsg ? extractToolUse(streamMsg) : [];
const hasStreamTools = showThinking && streamTools.length > 0;
const streamImages = streamMsg ? extractImages(streamMsg) : [];
const hasStreamImages = streamImages.length > 0;
const hasStreamToolStatus = showThinking && streamingTools.length > 0;
const shouldRenderStreaming = sending && (hasStreamText || hasStreamThinking || hasStreamTools || hasStreamImages || hasStreamToolStatus);
return (
<div className="flex flex-col -m-6" style={{ height: 'calc(100vh - 2.5rem)' }}>
@@ -106,20 +121,28 @@ export function Chat() {
))}
{/* Streaming message */}
{sending && hasStreamText && (
{shouldRenderStreaming && (
<ChatMessage
message={{
role: 'assistant',
content: streamMsg?.content ?? streamText,
timestamp: streamMsg?.timestamp ?? streamingTimestamp,
}}
message={(streamMsg
? {
...(streamMsg as Record<string, unknown>),
role: (typeof streamMsg.role === 'string' ? streamMsg.role : 'assistant') as RawMessage['role'],
content: streamMsg.content ?? streamText,
timestamp: streamMsg.timestamp ?? streamingTimestamp,
}
: {
role: 'assistant',
content: streamText,
timestamp: streamingTimestamp,
}) as RawMessage}
showThinking={showThinking}
isStreaming
streamingTools={streamingTools}
/>
)}
{/* Typing indicator when sending but no stream yet */}
{sending && !hasStreamText && (
{sending && !hasStreamText && !hasStreamThinking && !hasStreamTools && !hasStreamImages && !hasStreamToolStatus && (
<TypingIndicator />
)}
</>