feat: display agent avatar from OpenClaw identity config
Fetch agent identity via agent.identity.get WS method after connect. Display avatar in message bubbles (replacing Bot icon) and in the header (replacing the PinchChat logo when an avatar is configured). Falls back to default icons when no avatar is set.
This commit is contained in:
@@ -16,6 +16,7 @@ interface Props {
|
||||
sessionKey?: string;
|
||||
onSend: (text: string, attachments?: Array<{ mimeType: string; fileName: string; content: string }>) => void;
|
||||
onAbort: () => void;
|
||||
agentAvatarUrl?: string;
|
||||
}
|
||||
|
||||
function isNoReply(msg: ChatMessage): boolean {
|
||||
@@ -66,7 +67,7 @@ function getDateKey(ts: number): string {
|
||||
/** Threshold in pixels — if the user is within this distance of the bottom, auto-scroll */
|
||||
const SCROLL_THRESHOLD = 150;
|
||||
|
||||
export function Chat({ messages, isGenerating, isLoadingHistory, status, sessionKey, onSend, onAbort }: Props) {
|
||||
export function Chat({ messages, isGenerating, isLoadingHistory, status, sessionKey, onSend, onAbort, agentAvatarUrl }: Props) {
|
||||
const t = useT();
|
||||
const bottomRef = useRef<HTMLDivElement>(null);
|
||||
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
||||
@@ -161,7 +162,7 @@ export function Chat({ messages, isGenerating, isLoadingHistory, status, session
|
||||
<div className="flex-1 h-px bg-white/8" />
|
||||
</div>
|
||||
)}
|
||||
<ChatMessageComponent message={msg} onRetry={!isGenerating ? handleSend : undefined} />
|
||||
<ChatMessageComponent message={msg} onRetry={!isGenerating ? handleSend : undefined} agentAvatarUrl={agentAvatarUrl} />
|
||||
</div>
|
||||
))}
|
||||
{showTyping && <TypingIndicator />}
|
||||
|
||||
@@ -320,7 +320,7 @@ function SystemEventMessage({ message }: { message: ChatMessageType }) {
|
||||
);
|
||||
}
|
||||
|
||||
export function ChatMessageComponent({ message, onRetry }: { message: ChatMessageType; onRetry?: (text: string) => void }) {
|
||||
export function ChatMessageComponent({ message, onRetry, agentAvatarUrl }: { message: ChatMessageType; onRetry?: (text: string) => void; agentAvatarUrl?: string }) {
|
||||
useLocale(); // re-render on locale change
|
||||
const isUser = message.role === 'user';
|
||||
|
||||
@@ -342,10 +342,12 @@ export function ChatMessageComponent({ message, onRetry }: { message: ChatMessag
|
||||
return (
|
||||
<div className={`animate-fade-in flex gap-3 px-4 py-2 ${isUser ? 'flex-row-reverse' : ''}`}>
|
||||
{/* Avatar */}
|
||||
<div className="shrink-0 mt-1 flex h-9 w-9 items-center justify-center rounded-2xl border border-white/8 bg-zinc-800/40">
|
||||
<div className="shrink-0 mt-1 flex h-9 w-9 items-center justify-center rounded-2xl border border-white/8 bg-zinc-800/40 overflow-hidden">
|
||||
{isUser
|
||||
? <User className="h-4 w-4 text-cyan-200" />
|
||||
: <Bot className="h-4 w-4 text-cyan-200" />
|
||||
: agentAvatarUrl
|
||||
? <img src={agentAvatarUrl} alt="Agent" className="h-full w-full object-cover" />
|
||||
: <Bot className="h-4 w-4 text-cyan-200" />
|
||||
}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -15,9 +15,10 @@ interface Props {
|
||||
soundEnabled?: boolean;
|
||||
onToggleSound?: () => void;
|
||||
messages?: ChatMessage[];
|
||||
agentAvatarUrl?: string;
|
||||
}
|
||||
|
||||
export function Header({ status, sessionKey, onToggleSidebar, activeSessionData, onLogout, soundEnabled, onToggleSound, messages }: Props) {
|
||||
export function Header({ status, sessionKey, onToggleSidebar, activeSessionData, onLogout, soundEnabled, onToggleSound, messages, agentAvatarUrl }: Props) {
|
||||
const t = useT();
|
||||
const sessionLabel = activeSessionData ? sessionDisplayName(activeSessionData) : (sessionKey.split(':').pop() || sessionKey);
|
||||
|
||||
@@ -36,7 +37,7 @@ export function Header({ status, sessionKey, onToggleSidebar, activeSessionData,
|
||||
<Menu size={20} />
|
||||
</button>
|
||||
<div className="flex items-center gap-3 flex-1 min-w-0">
|
||||
<img src="/logo.png" alt="PinchChat" className="h-9 w-9 rounded-2xl" />
|
||||
<img src={agentAvatarUrl || '/logo.png'} alt="PinchChat" className="h-9 w-9 rounded-2xl object-cover" />
|
||||
<div className="min-w-0">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-semibold text-zinc-300 text-sm tracking-wide">{t('header.title')}</span>
|
||||
|
||||
Reference in New Issue
Block a user