From 0cf71b9e18e251d8ee9e21c357f98e5fbef96cec Mon Sep 17 00:00:00 2001 From: Marco Beretta <81851188+berry-13@users.noreply.github.com> Date: Sun, 14 Dec 2025 03:11:10 +0100 Subject: [PATCH] feat: Refactor image caching logic and integrate getAgentAvatarUrl for improved avatar handling --- .../src/components/Endpoints/EndpointIcon.tsx | 4 +-- client/src/components/Endpoints/URLIcon.tsx | 28 ++++++------------- client/src/utils/agents.tsx | 28 ++++++++++--------- 3 files changed, 25 insertions(+), 35 deletions(-) diff --git a/client/src/components/Endpoints/EndpointIcon.tsx b/client/src/components/Endpoints/EndpointIcon.tsx index 1320f1cc4e..9e4f2bb6a7 100644 --- a/client/src/components/Endpoints/EndpointIcon.tsx +++ b/client/src/components/Endpoints/EndpointIcon.tsx @@ -8,7 +8,7 @@ import type { } from 'librechat-data-provider'; import ConvoIconURL from '~/components/Endpoints/ConvoIconURL'; import MinimalIcon from '~/components/Endpoints/MinimalIcon'; -import { getIconEndpoint } from '~/utils'; +import { getIconEndpoint, getAgentAvatarUrl } from '~/utils'; export default function EndpointIcon({ conversation, @@ -42,7 +42,7 @@ export default function EndpointIcon({ const agent = endpoint === EModelEndpoint.agents ? agentsMap?.[conversation?.agent_id ?? ''] : null; - const agentAvatar = agent?.avatar?.filepath ?? ''; + const agentAvatar = getAgentAvatarUrl(agent) ?? ''; const iconURL = assistantAvatar || agentAvatar || convoIconURL; diff --git a/client/src/components/Endpoints/URLIcon.tsx b/client/src/components/Endpoints/URLIcon.tsx index 0e25ab175b..366289a6e4 100644 --- a/client/src/components/Endpoints/URLIcon.tsx +++ b/client/src/components/Endpoints/URLIcon.tsx @@ -2,6 +2,7 @@ import React, { memo, useState, useEffect } from 'react'; import { AlertCircle } from 'lucide-react'; import { Skeleton } from '@librechat/client'; import { icons } from '~/hooks/Endpoint/Icons'; +import { isImageCached } from '~/utils'; export const URLIcon = memo( ({ @@ -20,28 +21,15 @@ export const URLIcon = memo( endpoint?: string; }) => { const [imageError, setImageError] = useState(false); - const [isLoaded, setIsLoaded] = useState(() => { - // Check if image is already cached - if (typeof window !== 'undefined' && iconURL) { - const img = new Image(); - img.src = iconURL; - return img.complete && img.naturalWidth > 0; - } - return false; - }); + const [isLoaded, setIsLoaded] = useState(() => isImageCached(iconURL)); useEffect(() => { - // When URL changes, check if new image is cached - if (iconURL) { - const img = new Image(); - img.src = iconURL; - if (img.complete && img.naturalWidth > 0) { - setIsLoaded(true); - setImageError(false); - } else { - setIsLoaded(false); - setImageError(false); - } + if (isImageCached(iconURL)) { + setIsLoaded(true); + setImageError(false); + } else { + setIsLoaded(false); + setImageError(false); } }, [iconURL]); diff --git a/client/src/utils/agents.tsx b/client/src/utils/agents.tsx index 5793b127bb..a65577d1f3 100644 --- a/client/src/utils/agents.tsx +++ b/client/src/utils/agents.tsx @@ -3,6 +3,19 @@ import { Feather } from 'lucide-react'; import { Skeleton } from '@librechat/client'; import type t from 'librechat-data-provider'; +/** + * Checks if an image is already cached in the browser + * Returns true if image is complete and has valid dimensions + */ +export const isImageCached = (url: string | null | undefined): boolean => { + if (typeof window === 'undefined' || !url) { + return false; + } + const img = new Image(); + img.src = url; + return img.complete && img.naturalWidth > 0; +}; + /** * Extracts the avatar URL from an agent's avatar property * Handles both string and object formats @@ -32,22 +45,11 @@ const LazyAgentAvatar = ({ alt: string; imgClass: string; }) => { - const [isLoaded, setIsLoaded] = useState(() => { - // Check if image is already cached by creating a test image - if (typeof window !== 'undefined') { - const img = new Image(); - img.src = url; - return img.complete && img.naturalWidth > 0; - } - return false; - }); + const [isLoaded, setIsLoaded] = useState(() => isImageCached(url)); const [hasError, setHasError] = useState(false); useEffect(() => { - // When URL changes, check if new image is cached - const img = new Image(); - img.src = url; - if (img.complete && img.naturalWidth > 0) { + if (isImageCached(url)) { setIsLoaded(true); setHasError(false); } else {