From 7536ceec22c0487b800b17bbfc1feda65e958bea Mon Sep 17 00:00:00 2001 From: Marco Beretta <81851188+berry-13@users.noreply.github.com> Date: Sun, 5 Jul 2026 00:18:11 +0200 Subject: [PATCH] fix: hide bookmarking on forced-temporary chats before server conversion Opening a pre-existing permanent conversation under ephemeral retention only flips the composer isTemporary atom; the loaded conversation object stays non-temporary until a write converts it server-side. BookmarkMenu gated solely on isTemporaryConversation(conversation), so it kept exposing bookmarking on a chat that is already effectively temporary. Gate the menu on the forced-retention flag as well (matching how the composer already treats the chat), so permanent-chat actions are hidden until the server catches up. --- .../components/Chat/Menus/BookmarkMenu.tsx | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/client/src/components/Chat/Menus/BookmarkMenu.tsx b/client/src/components/Chat/Menus/BookmarkMenu.tsx index a42a917fbd..7cdb1a4793 100644 --- a/client/src/components/Chat/Menus/BookmarkMenu.tsx +++ b/client/src/components/Chat/Menus/BookmarkMenu.tsx @@ -3,18 +3,22 @@ import { useRecoilValue } from 'recoil'; import * as Ariakit from '@ariakit/react'; import { BookmarkPlusIcon } from 'lucide-react'; import { useQueryClient } from '@tanstack/react-query'; -import { Constants, QueryKeys } from 'librechat-data-provider'; import { BookmarkFilledIcon, BookmarkIcon } from '@radix-ui/react-icons'; +import { Constants, QueryKeys, isForcedTemporaryRetention } from 'librechat-data-provider'; import { DropdownPopup, TooltipAnchor, Spinner, useToastContext } from '@librechat/client'; import type { TConversationTag } from 'librechat-data-provider'; import type { FC } from 'react'; import type * as t from '~/common'; -import { useConversationTagsQuery, useTagConversationMutation } from '~/data-provider'; +import { + useGetStartupConfig, + useConversationTagsQuery, + useTagConversationMutation, +} from '~/data-provider'; import { BookmarkContext } from '~/Providers/BookmarkContext'; +import { cn, isTemporaryConversation, logger } from '~/utils'; import { BookmarkEditDialog } from '~/components/Bookmarks'; import { useBookmarkSuccess, useLocalize } from '~/hooks'; import { NotificationSeverity } from '~/common'; -import { cn, isTemporaryConversation, logger } from '~/utils'; import store from '~/store'; const BookmarkMenu: FC = () => { @@ -25,8 +29,16 @@ const BookmarkMenu: FC = () => { const conversation = useRecoilValue(store.conversationByIndex(0)) || undefined; const conversationId = conversation?.conversationId ?? ''; const updateConvoTags = useBookmarkSuccess(conversationId); + const { data: startupConfig } = useGetStartupConfig(); const tags = conversation?.tags; - const isTemporary = isTemporaryConversation(conversation); + /** + * A pre-existing permanent chat loaded under forced (ephemeral) retention stays + * non-temporary until the server converts it on the next write, so gate on the forced flag too + * to keep permanent-chat bookmarking hidden on a chat that is already effectively temporary. + */ + const isTemporary = + isTemporaryConversation(conversation) || + isForcedTemporaryRetention(startupConfig?.interface?.retentionMode); const menuId = useId(); const [isMenuOpen, setIsMenuOpen] = useState(false); const [isDialogOpen, setIsDialogOpen] = useState(false);