fix(web): 来源小字按消息角色区分语义——用户'来自',她'发送至'
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled

- SourceLabel 加 role: user 消息显示'来自 <deviceId>'(她收到,来自主人端), assistant 消息显示'发送至 <deviceId>'(她回复到的端)
- 修复: 之前她发的消息也标'来自 web:chrome:...' 语义错误,不是她来自用户设备
- 4 处调用点传 message.role; 前端 build 绿
This commit is contained in:
Aska committed 2026-09-07 15:07:06 +08:00
1 parent 1b0b5bf99c
commit aeb9fea64c
1 file changed
+9 -6
+9 -6
View File
@@ -120,11 +120,14 @@ function statusLabel(status: ToolStatus): string {
* concrete client the message came from, e.g. "来自 web:chrome:a1b2c3". Rendered
* only when a deviceId is present, so legacy/unlabelled messages stay clean. The
* Web client defaults to this label; other clients decide themselves. */
function SourceLabel({ deviceId }: { deviceId?: string }): React.ReactNode {
function SourceLabel({ deviceId, role }: { deviceId?: string; role?: string }): React.ReactNode {
if (!deviceId) return null;
// A user message is received FROM a client; an assistant reply goes TO the
// client that prompted it. Semantic direction differs — "来自" vs "发送至".
const dir = role === "assistant" ? "发送至" : "来自";
return (
<div className="text-[10px] leading-tight text-[var(--mu-text-lo)]">
来自 {deviceId}
{dir} {deviceId}
</div>
);
}
@@ -213,7 +216,7 @@ function AssistantParaBubble({
{full && message.mood ? (
<div className="mb-1 text-xs text-[var(--mu-text-lo)]">心情 · {message.mood}</div>
) : null}
{full ? <SourceLabel deviceId={message.deviceId} /> : null}
{full ? <SourceLabel deviceId={message.deviceId} role={message.role} /> : null}
{full ? <WakePath active={active} /> : null}
{full ? <ThinkingBlock text={message.thinking} streaming={message.streaming} /> : null}
{full ? message.tools?.map((t, i) => <ToolCard key={i} tool={t} />) : null}
@@ -245,7 +248,7 @@ function UserParaBubble({
) : null}
<span className="whitespace-pre-wrap">{renderContent(text)}</span>
</div>
{full ? <SourceLabel deviceId={message.deviceId} /> : null}
{full ? <SourceLabel deviceId={message.deviceId} role={message.role} /> : null}
</div>
);
}
@@ -319,7 +322,7 @@ function UserBubble({ message, mode }: { message: ChatMessage; mode: Mode }): Re
) : null}
{body}
</div>
<SourceLabel deviceId={message.deviceId} />
<SourceLabel deviceId={message.deviceId} role={message.role} />
<SenderLabel name={message.senderName} />
</div>
);
@@ -345,7 +348,7 @@ function AssistantBubble({
{message.mood ? (
<div className="mb-1 text-xs text-[var(--mu-text-lo)]">心情 · {message.mood}</div>
) : null}
<SourceLabel deviceId={message.deviceId} />
<SourceLabel deviceId={message.deviceId} role={message.role} />
<WakePath active={active} />
<ThinkingBlock text={message.thinking} streaming={message.streaming} />
{message.tools?.map((t, i) => <ToolCard key={i} tool={t} />)}