fix(chat): stabilize message identities

This commit is contained in:
2026-07-20 18:30:21 +08:00
parent 159e8bfd59
commit 1e13f94b5d
33 changed files with 718 additions and 212 deletions
+19 -10
View File
@@ -16,7 +16,8 @@ import styles from "./chat-area.module.css";
export interface MessageBubbleProps {
characterId: string;
messageId?: string;
displayMessageId: string;
remoteMessageId?: string;
content: string;
imageUrl?: string | null;
imagePaywalled?: boolean;
@@ -27,15 +28,21 @@ export interface MessageBubbleProps {
lockedPrivate?: boolean | null;
privateMessageHint?: string | null;
isUnlockingMessage?: boolean;
onUnlockPrivateMessage?: (messageId: string) => void;
onUnlockVoiceMessage?: (messageId: string) => void;
onUnlockImageMessage?: (messageId: string) => void;
onOpenImage?: (messageId: string) => void;
onUnlockPrivateMessage?: ChatMessageAction;
onUnlockVoiceMessage?: ChatMessageAction;
onUnlockImageMessage?: ChatMessageAction;
onOpenImage?: (displayMessageId: string) => void;
}
type ChatMessageAction = (
displayMessageId: string,
remoteMessageId?: string,
) => void;
export function MessageBubble({
characterId,
messageId,
displayMessageId,
remoteMessageId,
content,
imageUrl,
imagePaywalled,
@@ -57,18 +64,19 @@ export function MessageBubble({
return (
<div
className={styles.bubbleRowAi}
data-chat-message-id={messageId}
data-chat-message-id={displayMessageId}
aria-label="AI message"
>
<MessageAvatar isFromAI={true} />
<div className={styles.bubbleInlineSpacer} aria-hidden="true" />
<MessageContent
characterId={characterId}
displayMessageId={displayMessageId}
remoteMessageId={remoteMessageId}
content={content}
imageUrl={imageUrl}
imagePaywalled={imagePaywalled}
audioUrl={audioUrl}
messageId={messageId}
isFromAI={true}
locked={locked}
lockReason={lockReason}
@@ -88,17 +96,18 @@ export function MessageBubble({
return (
<div
className={styles.bubbleRowUser}
data-chat-message-id={messageId}
data-chat-message-id={displayMessageId}
aria-label="User message"
>
<div className={styles.bubbleAvatarSpacer} aria-hidden="true" />
<MessageContent
characterId={characterId}
displayMessageId={displayMessageId}
remoteMessageId={remoteMessageId}
content={content}
imageUrl={imageUrl}
imagePaywalled={imagePaywalled}
audioUrl={audioUrl}
messageId={messageId}
isFromAI={false}
locked={locked}
lockReason={lockReason}