fix: isolate detail mode chat surface
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-02-17 14:36:25 +08:00
parent dde1b95f25
commit 0fa1fecc59

View File

@ -582,6 +582,7 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
brandTone: "",
bannedWords: "",
});
const [detailModeMessageStartIndex, setDetailModeMessageStartIndex] = useState(0);
const canvasId = useMemo(() => toRawCanvasChatId(chatId), [chatId]);
const [activeChatId, setActiveChatId] = useState<string>(chatId);
const [chatSessions, setChatSessions] = useState<CanvasChatSession[]>([]);
@ -591,6 +592,7 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
const videoSlotInputRefs = useRef<Array<HTMLInputElement | null>>([]);
const detailSlotInputRefs = useRef<Array<HTMLInputElement | null>>([]);
const textareaRef = useRef<HTMLTextAreaElement>(null);
const detailModeSwitchRef = useRef(false);
const hiddenPromptRef = useRef<string | null>(null);
const autoContextRef = useRef<string | null>(null);
const pendingLaunchRef = useRef<CanvasLaunchPayload | null>(null);
@ -2791,6 +2793,18 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
return tagKeys.has(`image|${att.url}`);
}));
}, []);
useEffect(() => {
if (isDetailGenerationMode && !detailModeSwitchRef.current) {
setDetailModeMessageStartIndex(messages.length);
}
detailModeSwitchRef.current = isDetailGenerationMode;
}, [isDetailGenerationMode, messages.length]);
const visibleMessages = useMemo(
() => (isDetailGenerationMode ? messages.slice(detailModeMessageStartIndex) : messages),
[detailModeMessageStartIndex, isDetailGenerationMode, messages]
);
const isLoading = status === 'streaming' || status === 'submitted';
const isSubmitting = isLoading || isDetailGenerating;
@ -2817,8 +2831,8 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
currentVideoImageLimit.max > 0 &&
videoFrameSlots.length === 0
);
const lastUserIndexForMarkers = messages.findLastIndex(m => m.role === "user");
const messagesAfterLastUser = lastUserIndexForMarkers >= 0 ? messages.slice(lastUserIndexForMarkers + 1) : messages;
const lastUserIndexForMarkers = visibleMessages.findLastIndex(m => m.role === "user");
const messagesAfterLastUser = lastUserIndexForMarkers >= 0 ? visibleMessages.slice(lastUserIndexForMarkers + 1) : visibleMessages;
const hasGenerationStart = messagesAfterLastUser.some(msg =>
msg.role === "assistant" && msg.parts?.some(
(part: any) => part.type === "text" && part.text?.includes("<!-- IMAGE_GENERATION_START -->")
@ -2989,11 +3003,11 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
<ScrollArea
className={cn(
"flex-1 p-4",
isDetailGenerationMode && messages.length === 0 ? "pt-10" : "pt-16"
isDetailGenerationMode && visibleMessages.length === 0 ? "pt-10" : "pt-16"
)}
>
<div className="space-y-6">
{messages.length === 0 && (
{!isDetailGenerationMode && visibleMessages.length === 0 && (
<div className={cn("flex flex-col h-full", isDetailGenerationMode ? "pt-0" : "pt-4")}>
{/* Greeting */}
<div className={cn(isDetailGenerationMode ? "mb-4" : "mb-8")}>
@ -3030,7 +3044,7 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
</div>
)}
{messages.map((message) => {
{visibleMessages.map((message) => {
// 🆕 清理消息中的内部标记并检查是否有实际内容
const rawParts = message.parts || [];
const cleanedParts = rawParts.map((part: any) => {
@ -3299,7 +3313,7 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
<div
className={cn(
"mx-3 mt-3 overflow-y-auto rounded-2xl border border-black/10 bg-white/95 p-3 pr-2",
messages.length === 0 ? "max-h-[62vh]" : "max-h-[54vh]"
visibleMessages.length === 0 ? "max-h-[62vh]" : "max-h-[54vh]"
)}
>
<div className="flex items-start justify-between gap-3">