From 707d8cb065ddac79583584586d698443969a9d3c Mon Sep 17 00:00:00 2001 From: Matthew Hrehirchuk Date: Thu, 2 Apr 2026 12:02:54 -0600 Subject: [PATCH] fix(sidebar): use any api keys for context menu regenerations --- src/components/sidebar/thread-item.tsx | 6 +++--- src/features/chat/actions.ts | 14 ++++++++------ src/features/chat/hooks/use-threads.ts | 9 +++++---- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/components/sidebar/thread-item.tsx b/src/components/sidebar/thread-item.tsx index 0cca3d9..5044683 100644 --- a/src/components/sidebar/thread-item.tsx +++ b/src/components/sidebar/thread-item.tsx @@ -108,7 +108,7 @@ function ThreadItemComponent({ }: ThreadItemProps) { const router = useRouter(); const pathname = usePathname(); - const openrouterKey = useChatUIStore(state => state.clientKeys.openrouter); + const clientKeys = useChatUIStore(state => state.clientKeys); const isStreaming = useChatUIStore(state => state.streamingThreadId === id); const { data: settings } = useUserSettings(); const sidebarIconsDisabled = settings?.showSidebarIcons ?? false; @@ -172,7 +172,7 @@ function ThreadItemComponent({ const handleRegenerateNameClick = async () => { try { - await regenerateThreadNameMutation.mutateAsync({ threadId: id, clientKey: openrouterKey ?? undefined, useAllMessages: true }); + await regenerateThreadNameMutation.mutateAsync({ threadId: id, clientKeys: Object.keys(clientKeys).length > 0 ? clientKeys : undefined, useAllMessages: true }); toast.success("Thread name regenerated"); } catch (error) { @@ -183,7 +183,7 @@ function ThreadItemComponent({ const handleRegenerateIconClick = async () => { try { - await regenerateThreadIconMutation.mutateAsync({ threadId: id, clientKey: openrouterKey ?? undefined }); + await regenerateThreadIconMutation.mutateAsync({ threadId: id, clientKeys: Object.keys(clientKeys).length > 0 ? clientKeys : undefined }); toast.success("Thread icon regenerated"); } catch (error) { diff --git a/src/features/chat/actions.ts b/src/features/chat/actions.ts index f385382..95f9720 100644 --- a/src/features/chat/actions.ts +++ b/src/features/chat/actions.ts @@ -2,6 +2,7 @@ import type { TagRow } from "~/features/chat/queries"; import type { ChatUIMessage } from "~/features/chat/types"; +import type { ApiKeyProvider } from "~/lib/api-keys/types"; import type { ThreadIcon } from "~/lib/db/schema/chat"; import { deleteFile } from "~/features/attachments/lib/storage"; @@ -156,10 +157,11 @@ export async function archiveThread(threadId: string, archive: boolean): Promise * Ownership is verified atomically by the renameThreadById query. * * @param threadId ID of the thread to rename - * @param clientKey Optional API key provided by the client (from localStorage) + * @param clientKeys Optional API keys provided by the client (from localStorage) + * @param useAllMessages Optional flag to send all messages for name context, instead of just the initial. * @return {Promise} The new title */ -export async function regenerateThreadName(threadId: string, clientKey?: string, useAllMessages = false): Promise { +export async function regenerateThreadName(threadId: string, clientKeys?: Partial>, useAllMessages = false): Promise { const session = await getRequiredSession(); const userId = session.user.id; @@ -167,7 +169,7 @@ export async function regenerateThreadName(threadId: string, clientKey?: string, // Fetch API keys, settings, tier, and messages in parallel const { getUserSettingsAndKeys } = await import("~/features/settings/queries"); const [{ settings, resolvedKeys }, threadMessages, tier] = await Promise.all([ - getUserSettingsAndKeys(userId, clientKey ? { openrouter: clientKey } : undefined), + getUserSettingsAndKeys(userId, clientKeys), getMessagesByThreadId(threadId), getUserTier(userId), ]); @@ -223,17 +225,17 @@ export async function regenerateThreadName(threadId: string, clientKey?: string, * Ownership is verified atomically by the updateThreadIcon query. * * @param threadId ID of the thread to update - * @param clientKey Optional API key provided by the client (from localStorage) + * @param clientKeys Optional API keys provided by the client (from localStorage) * @return {Promise} The new icon */ -export async function regenerateThreadIcon(threadId: string, clientKey?: string): Promise { +export async function regenerateThreadIcon(threadId: string, clientKeys?: Partial>): Promise { const session = await getRequiredSession(); const userId = session.user.id; const { getUserSettingsAndKeys } = await import("~/features/settings/queries"); const [{ settings, resolvedKeys }, threadMessages, tier] = await Promise.all([ - getUserSettingsAndKeys(userId, clientKey ? { openrouter: clientKey } : undefined), + getUserSettingsAndKeys(userId, clientKeys), getMessagesByThreadId(threadId), getUserTier(userId), ]); diff --git a/src/features/chat/hooks/use-threads.ts b/src/features/chat/hooks/use-threads.ts index d50fc77..44c2082 100644 --- a/src/features/chat/hooks/use-threads.ts +++ b/src/features/chat/hooks/use-threads.ts @@ -6,6 +6,7 @@ import { useInfiniteQuery, useMutation, useQuery, useQueryClient } from "@tansta import { useMemo } from "react"; import type { GroupedThreads, TagGroup } from "~/features/chat/utils/thread-grouper"; +import type { ApiKeyProvider } from "~/lib/api-keys/types"; import type { ThreadIcon } from "~/lib/db/schema/chat"; import { archiveThread, deleteThread, fetchThreadStats, regenerateThreadIcon, regenerateThreadName, renameThread, setThreadIcon } from "~/features/chat/actions"; @@ -151,8 +152,8 @@ export function useRegenerateThreadName() { const queryClient = useQueryClient(); return useMutation({ - mutationFn: ({ threadId, clientKey, useAllMessages }: { threadId: string; clientKey?: string; useAllMessages?: boolean }) => - regenerateThreadName(threadId, clientKey, useAllMessages), + mutationFn: ({ threadId, clientKeys, useAllMessages }: { threadId: string; clientKeys?: Partial>; useAllMessages?: boolean }) => + regenerateThreadName(threadId, clientKeys, useAllMessages), onSuccess: () => { queryClient.invalidateQueries({ queryKey: THREADS_KEY }); }, @@ -217,8 +218,8 @@ export function useRegenerateThreadIcon() { const queryClient = useQueryClient(); return useMutation({ - mutationFn: ({ threadId, clientKey }: { threadId: string; clientKey?: string }) => - regenerateThreadIcon(threadId, clientKey), + mutationFn: ({ threadId, clientKeys }: { threadId: string; clientKeys?: Partial> }) => + regenerateThreadIcon(threadId, clientKeys), onSuccess: (newIcon, { threadId }) => { queryClient.setQueryData>(THREADS_KEY, (old) => { if (!old)