fix: 按 speaker.type 区分消息左右与头像,并改为 iMessage 气泡样式
parent
b1df40e983
commit
e6116c1c80
|
|
@ -15,7 +15,11 @@ export interface ToolCallTrace {
|
||||||
|
|
||||||
export interface ChatMessage {
|
export interface ChatMessage {
|
||||||
id: string;
|
id: string;
|
||||||
role: 'user' | 'assistant';
|
role: 'user' | 'assistant' | 'agent' | 'system';
|
||||||
|
speaker?: {
|
||||||
|
id: string;
|
||||||
|
type: 'user' | 'agent';
|
||||||
|
};
|
||||||
content: string;
|
content: string;
|
||||||
reasoning?: string | null;
|
reasoning?: string | null;
|
||||||
parentId?: string | null;
|
parentId?: string | null;
|
||||||
|
|
@ -73,4 +77,3 @@ export const ChatAttachmentsAPI = {
|
||||||
return api.post<{ files: ChatAttachment[] }>('/chat/attachments', fd).then((r) => r.data);
|
return api.post<{ files: ChatAttachment[] }>('/chat/attachments', fd).then((r) => r.data);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ export default function ChatBody(props: {
|
||||||
agentList={agentList}
|
agentList={agentList}
|
||||||
currentAgentId={currentAgentId}
|
currentAgentId={currentAgentId}
|
||||||
highlighted={highlightId === m.id}
|
highlighted={highlightId === m.id}
|
||||||
branch={m.role === 'assistant' && m.parentId ? branches[m.parentId] : undefined}
|
branch={((m as any)?.speaker?.type ? (m as any).speaker.type === 'agent' : m.role === 'assistant') && m.parentId ? branches[m.parentId] : undefined}
|
||||||
busy={sending}
|
busy={sending}
|
||||||
onRegenerate={onRegenerate}
|
onRegenerate={onRegenerate}
|
||||||
onSwitchBranch={onSwitchBranch}
|
onSwitchBranch={onSwitchBranch}
|
||||||
|
|
@ -76,7 +76,9 @@ export default function ChatBody(props: {
|
||||||
const streamingAgent = agentList.find(a => a.id === streamingAgentId);
|
const streamingAgent = agentList.find(a => a.id === streamingAgentId);
|
||||||
if (streamingAgent) {
|
if (streamingAgent) {
|
||||||
return (
|
return (
|
||||||
<Avatar src={streamingAgent.avatar} size={36} style={{ flexShrink: 0, marginTop: 2 }} />
|
<Avatar src={streamingAgent.avatar} size={36} style={{ flexShrink: 0, marginTop: 2, backgroundColor: '#52c41a' }}>
|
||||||
|
{streamingAgent.name?.charAt(0)?.toUpperCase() || 'A'}
|
||||||
|
</Avatar>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ function summarize(content: string) {
|
||||||
|
|
||||||
export default function ChatOutline(props: { messages: ChatMessage[]; onJump: (id: string) => void; activeId?: string | null }) {
|
export default function ChatOutline(props: { messages: ChatMessage[]; onJump: (id: string) => void; activeId?: string | null }) {
|
||||||
const { messages, onJump, activeId } = props;
|
const { messages, onJump, activeId } = props;
|
||||||
const items = messages.filter((m) => m.role === 'assistant');
|
const items = messages.filter((m) => ((m as any)?.speaker?.type ? (m as any).speaker.type === 'agent' : m.role === 'assistant'));
|
||||||
|
|
||||||
if (items.length === 0) return null;
|
if (items.length === 0) return null;
|
||||||
|
|
||||||
|
|
@ -38,4 +38,3 @@ export default function ChatOutline(props: { messages: ChatMessage[]; onJump: (i
|
||||||
</aside>
|
</aside>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,12 @@ export default function MessageItem(props: {
|
||||||
}) {
|
}) {
|
||||||
const { message, agentList, currentAgentId, highlighted, branch, busy, onRegenerate, onSwitchBranch, onCopy } = props;
|
const { message, agentList, currentAgentId, highlighted, branch, busy, onRegenerate, onSwitchBranch, onCopy } = props;
|
||||||
|
|
||||||
|
const speakerType = (message as any)?.speaker?.type as ('user' | 'agent' | undefined);
|
||||||
|
const isUser = speakerType ? speakerType === 'user' : message.role === 'user';
|
||||||
|
const bubbleRole = isUser ? 'user' : 'assistant';
|
||||||
|
|
||||||
// 获取回答者 Agent 信息
|
// 获取回答者 Agent 信息
|
||||||
const answerAgentId = message.agent_id || (message.role === 'assistant' ? currentAgentId : undefined);
|
const answerAgentId = message.agent_id || (!isUser ? currentAgentId : undefined);
|
||||||
const answerAgent = answerAgentId ? agentList.find(a => a.id === answerAgentId) : undefined;
|
const answerAgent = answerAgentId ? agentList.find(a => a.id === answerAgentId) : undefined;
|
||||||
const hasBranches = !!branch && branch.total > 1;
|
const hasBranches = !!branch && branch.total > 1;
|
||||||
const activeIdx = branch?.activeIndex ?? 0;
|
const activeIdx = branch?.activeIndex ?? 0;
|
||||||
|
|
@ -49,9 +53,8 @@ export default function MessageItem(props: {
|
||||||
transition: 'background 0.4s, padding 0.4s'
|
transition: 'background 0.4s, padding 0.4s'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{message.role === 'assistant' ? (
|
{!isUser ? (
|
||||||
<div style={{ display: 'flex', gap: 12, alignItems: 'flex-start' }}>
|
<div style={{ display: 'flex', gap: 12, alignItems: 'flex-start' }}>
|
||||||
{/* AGENT: 头像在左侧,内容在右侧(靠左对齐) */}
|
|
||||||
<Avatar
|
<Avatar
|
||||||
src={answerAgent?.avatar}
|
src={answerAgent?.avatar}
|
||||||
size={36}
|
size={36}
|
||||||
|
|
@ -74,7 +77,7 @@ export default function MessageItem(props: {
|
||||||
{answerAgent?.name || 'AI'}
|
{answerAgent?.name || 'AI'}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className={`bubble ${message.role}`}>
|
<div className={`bubble ${bubbleRole}`}>
|
||||||
<Markdown>{message.content}</Markdown>
|
<Markdown>{message.content}</Markdown>
|
||||||
</div>
|
</div>
|
||||||
<div className="monica-msg-actions">
|
<div className="monica-msg-actions">
|
||||||
|
|
@ -124,8 +127,7 @@ export default function MessageItem(props: {
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div style={{ display: 'flex', gap: 12, alignItems: 'flex-start', justifyContent: 'flex-end' }}>
|
<div style={{ display: 'flex', gap: 12, alignItems: 'flex-start', justifyContent: 'flex-end' }}>
|
||||||
{/* 用户: 头像在右侧,内容在左侧(靠右对齐) */}
|
<div style={{ flex: 1, minWidth: 0, maxWidth: '78%', display: 'flex', flexDirection: 'column', alignItems: 'flex-end' }}>
|
||||||
<div style={{ maxWidth: '78%', display: 'flex', flexDirection: 'column', alignItems: 'flex-end' }}>
|
|
||||||
<div style={{
|
<div style={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
|
@ -140,7 +142,7 @@ export default function MessageItem(props: {
|
||||||
我
|
我
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className={`bubble ${message.role}`}>
|
<div className={`bubble ${bubbleRole}`}>
|
||||||
{message.content.includes(' ? (
|
{message.content.includes(' ? (
|
||||||
<Markdown>{message.content}</Markdown>
|
<Markdown>{message.content}</Markdown>
|
||||||
) : (
|
) : (
|
||||||
|
|
|
||||||
|
|
@ -628,6 +628,7 @@ body {
|
||||||
|
|
||||||
.bubble {
|
.bubble {
|
||||||
max-width: 78%;
|
max-width: 78%;
|
||||||
|
display: inline-block;
|
||||||
padding: 14px 18px;
|
padding: 14px 18px;
|
||||||
border-radius: 14px;
|
border-radius: 14px;
|
||||||
margin-bottom: 14px;
|
margin-bottom: 14px;
|
||||||
|
|
@ -638,18 +639,18 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.bubble.user {
|
.bubble.user {
|
||||||
background: var(--color-brand-soft);
|
background: #0a84ff;
|
||||||
color: var(--color-text);
|
color: #ffffff;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
border-bottom-right-radius: 5px;
|
border-bottom-right-radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bubble.assistant {
|
.bubble.assistant {
|
||||||
background: #ffffff;
|
background: #e9e9eb;
|
||||||
color: var(--color-text);
|
color: #111827;
|
||||||
border: 1px solid var(--color-border);
|
border: 0;
|
||||||
border-bottom-left-radius: 5px;
|
border-bottom-left-radius: 5px;
|
||||||
box-shadow: var(--shadow-xs);
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bubble.assistant p {
|
.bubble.assistant p {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue