From 8186d4fa291041d82a77edc8a1cc6efa73e55605 Mon Sep 17 00:00:00 2001 From: SuYao Date: Fri, 16 Jan 2026 23:05:13 +0800 Subject: [PATCH] fix: handle trailing slashes in API URLs for image generation (#12492) fix: normalize provider apiHost at source to handle trailing slashes Normalize provider apiHost by removing trailing slashes in useProvider.ts selectors. This ensures consistent URL concatenation across the entire application, including image generation pages, without modifying each usage point individually. Fixes #12485 Co-authored-by: Claude Opus 4.5 --- src/renderer/src/hooks/useProvider.ts | 32 ++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/renderer/src/hooks/useProvider.ts b/src/renderer/src/hooks/useProvider.ts index be4ed772fb..960d2929d0 100644 --- a/src/renderer/src/hooks/useProvider.ts +++ b/src/renderer/src/hooks/useProvider.ts @@ -13,12 +13,28 @@ import { } from '@renderer/store/llm' import type { Assistant, Model, Provider } from '@renderer/types' import { isSystemProvider } from '@renderer/types' +import { withoutTrailingSlash } from '@renderer/utils/api' import { useDefaultModel } from './useAssistant' +/** + * Normalizes provider apiHost by removing trailing slashes. + * This ensures consistent URL concatenation across the application. + */ +function normalizeProvider(provider: T): T { + return { + ...provider, + apiHost: withoutTrailingSlash(provider.apiHost) + } +} + const selectEnabledProviders = createSelector( (state) => state.llm.providers, - (providers) => providers.filter((p) => p.enabled).concat(CHERRYAI_PROVIDER) + (providers) => + providers + .map(normalizeProvider) + .filter((p) => p.enabled) + .concat(CHERRYAI_PROVIDER) ) export function useProviders() { @@ -35,21 +51,25 @@ export function useProviders() { } export function useSystemProviders() { - return useAppSelector((state) => state.llm.providers.filter((p) => isSystemProvider(p))) + return useAppSelector((state) => state.llm.providers.filter((p) => isSystemProvider(p)).map(normalizeProvider)) } export function useUserProviders() { - return useAppSelector((state) => state.llm.providers.filter((p) => !isSystemProvider(p))) + return useAppSelector((state) => state.llm.providers.filter((p) => !isSystemProvider(p)).map(normalizeProvider)) } export function useAllProviders() { - return useAppSelector((state) => state.llm.providers) + return useAppSelector((state) => state.llm.providers.map(normalizeProvider)) } export function useProvider(id: string) { const provider = - useAppSelector((state) => state.llm.providers.concat([CHERRYAI_PROVIDER]).find((p) => p.id === id)) || - getDefaultProvider() + useAppSelector((state) => + state.llm.providers + .concat([CHERRYAI_PROVIDER]) + .map(normalizeProvider) + .find((p) => p.id === id) + ) || getDefaultProvider() const dispatch = useAppDispatch() return {