56 lines
2.0 KiB
TypeScript
56 lines
2.0 KiB
TypeScript
/**
|
|
* MessageItem — 单条消息路由组件
|
|
*
|
|
* 根据消息 role 路由到对应的子组件渲染。
|
|
*
|
|
* F1 性能优化: 使用 React.memo 包裹,避免流式 delta 触发历史消息重渲染。
|
|
* 浅比较策略:message 引用变化(store 仅替换最后一条)或 isStreaming 变化时才重渲染。
|
|
* 历史消息的 message 引用在 delta 流中保持不变,因此可跳过 re-render。
|
|
*/
|
|
|
|
import { memo } from 'react';
|
|
import type { ChatMessage } from '@renderer/stores/agent-store';
|
|
import { UserMessage } from './UserMessage';
|
|
import { AssistantMessage } from './AssistantMessage';
|
|
import { SystemMessage } from './SystemMessage';
|
|
|
|
interface MessageItemProps {
|
|
message: ChatMessage;
|
|
isLast?: boolean;
|
|
isStreaming?: boolean;
|
|
}
|
|
|
|
function MessageItemImpl({ message, isLast, isStreaming }: MessageItemProps): React.JSX.Element | null {
|
|
switch (message.role) {
|
|
case 'user':
|
|
return <UserMessage message={message} />;
|
|
|
|
case 'assistant':
|
|
return (
|
|
<AssistantMessage
|
|
message={message}
|
|
isStreaming={isLast && isStreaming}
|
|
/>
|
|
);
|
|
|
|
case 'tool':
|
|
// #38 修复: 与 AgentStore.setCurrentSession 的过滤逻辑保持一致,
|
|
// 不在 UI 中渲染独立的 tool 消息卡片。
|
|
// tool 结果已包含在 assistant 消息的 toolCalls 中(见 AssistantMessage),
|
|
// 独立的 tool 消息仅用于 LLM API 上下文,不需要在前端显示为独立卡片。
|
|
return null;
|
|
|
|
case 'system':
|
|
default:
|
|
return <SystemMessage message={message} />;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* F1: memo 默认浅比较 props。
|
|
* - message 是对象引用,store 更新最后一条时只替换最后一条,历史消息引用不变 → 跳过 re-render
|
|
* - isStreaming 是 boolean,流式过程中值不变(持续 true),流结束才变化一次 → 历史消息仅重渲染一次
|
|
* - isLast 是 boolean,仅在最后一条切换时变化
|
|
*/
|
|
export const MessageItem = memo(MessageItemImpl);
|