diff --git a/pages/link/callback_openrouter.tsx b/pages/link/callback_openrouter.tsx index b70868ea4..6479c20b0 100644 --- a/pages/link/callback_openrouter.tsx +++ b/pages/link/callback_openrouter.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { Box, Typography } from '@mui/joy'; -import { useModelsStore } from '~/common/stores/llms/store-llms'; +import { llmsStoreActions } from '~/common/stores/llms/store-llms'; import { InlineError } from '~/common/components/InlineError'; import { apiQuery } from '~/common/util/trpc.client'; @@ -30,7 +30,7 @@ function CallbackOpenRouterPage(props: { openRouterCode: string | undefined }) { return; // 1. Save the key as the client key - useModelsStore.getState().setOpenRoutersKey(openRouterKey); + llmsStoreActions().setOpenRouterKey(openRouterKey); // 2. Navigate to the chat app void navigateToIndex(true); //.then(openModelsSetup); diff --git a/src/apps/beam/AppBeam.tsx b/src/apps/beam/AppBeam.tsx index d5499720c..d579c0c94 100644 --- a/src/apps/beam/AppBeam.tsx +++ b/src/apps/beam/AppBeam.tsx @@ -10,8 +10,8 @@ import { createBeamVanillaStore } from '~/modules/beam/store-beam-vanilla'; import { OptimaToolbarIn } from '~/common/layout/optima/portals/OptimaPortalsIn'; import { createDConversation, DConversation } from '~/common/stores/chat/chat.conversation'; import { createDMessageTextContent, DMessage } from '~/common/stores/chat/chat.message'; +import { getChatLLMId } from '~/common/stores/llms/store-llms'; import { useIsMobile } from '~/common/components/useMatchMedia'; -import { useModelsStore } from '~/common/stores/llms/store-llms'; function initTestConversation(): DConversation { @@ -22,7 +22,7 @@ function initTestConversation(): DConversation { } function initTestBeamStore(messages: DMessage[], beamStore: BeamStoreApi = createBeamVanillaStore()): BeamStoreApi { - beamStore.getState().open(messages, useModelsStore.getState().chatLLMId, (content) => alert(content)); + beamStore.getState().open(messages, getChatLLMId(), (content) => alert(content)); return beamStore; } diff --git a/src/apps/chat/components/layout-bar/useLLMDropdown.tsx b/src/apps/chat/components/layout-bar/useLLMDropdown.tsx index 56fd5e6dd..469277f1f 100644 --- a/src/apps/chat/components/layout-bar/useLLMDropdown.tsx +++ b/src/apps/chat/components/layout-bar/useLLMDropdown.tsx @@ -8,12 +8,12 @@ import SettingsIcon from '@mui/icons-material/Settings'; import { findModelVendor } from '~/modules/llms/vendors/vendors.registry'; import type { DLLM, DLLMId } from '~/common/stores/llms/llms.types'; - import type { DModelsServiceId } from '~/common/stores/llms/modelsservice.types'; +import type { DModelsServiceId } from '~/common/stores/llms/modelsservice.types'; import { DebouncedInputMemo } from '~/common/components/DebouncedInput'; import { DropdownItems, PageBarDropdownMemo } from '~/common/layout/optima/components/PageBarDropdown'; import { GoodTooltip } from '~/common/components/GoodTooltip'; import { KeyStroke } from '~/common/components/KeyStroke'; -import { findModelsServiceOrNull, useModelsStore } from '~/common/stores/llms/store-llms'; +import { findModelsServiceOrNull, llmsStoreActions, useModelsStore } from '~/common/stores/llms/store-llms'; import { optimaActions, optimaOpenModels } from '~/common/layout/optima/useOptima'; @@ -181,15 +181,14 @@ function LLMDropdown(props: { export function useChatLLMDropdown() { // external state - const { llms, chatLLMId, setChatLLMId } = useModelsStore(useShallow(state => ({ + const { llms, chatLLMId } = useModelsStore(useShallow(state => ({ llms: state.llms, // NOTE: we don't need a deep comparison as we reference the same array chatLLMId: state.chatLLMId, - setChatLLMId: state.setChatLLMId, }))); const chatLLMDropdown = React.useMemo(() => { - return ; - }, [llms, chatLLMId, setChatLLMId]); + return ; + }, [llms, chatLLMId]); return { chatLLMId, chatLLMDropdown }; } diff --git a/src/common/chat-overlay/ConversationHandler.ts b/src/common/chat-overlay/ConversationHandler.ts index 0f767df37..8871c0f0c 100644 --- a/src/common/chat-overlay/ConversationHandler.ts +++ b/src/common/chat-overlay/ConversationHandler.ts @@ -10,7 +10,7 @@ import type { DLLMId } from '~/common/stores/llms/llms.types'; import { ChatActions, getConversationSystemPurposeId, useChatStore } from '~/common/stores/chat/store-chats'; import { createDMessageEmpty, createDMessageFromFragments, createDMessagePlaceholderIncomplete, createDMessageTextContent, DMessage, DMessageId } from '~/common/stores/chat/chat.message'; import { createTextContentFragment, DMessageFragment, DMessageFragmentId } from '~/common/stores/chat/chat.fragments'; -import { useModelsStore } from '~/common/stores/llms/store-llms'; +import { getChatLLMId } from '~/common/stores/llms/store-llms'; import { createDEphemeral } from './store-ephemeralsoverlay-slice'; import { createPerChatVanillaStore } from './store-chat-overlay'; @@ -176,8 +176,8 @@ export class ConversationHandler { terminateKeepingSettings(); }; - beamOpen(viewHistory, useModelsStore.getState().chatLLMId, onBeamSuccess); - importMessages.length && beamImportRays(importMessages, useModelsStore.getState().chatLLMId); + beamOpen(viewHistory, getChatLLMId(), onBeamSuccess); + importMessages.length && beamImportRays(importMessages, getChatLLMId()); } diff --git a/src/common/components/forms/useFormRadioLlmType.tsx b/src/common/components/forms/useFormRadioLlmType.tsx index 54c5205c0..9117434f4 100644 --- a/src/common/components/forms/useFormRadioLlmType.tsx +++ b/src/common/components/forms/useFormRadioLlmType.tsx @@ -1,8 +1,7 @@ import * as React from 'react'; -import { useShallow } from 'zustand/react/shallow'; import type { DLLM } from '~/common/stores/llms/llms.types'; -import { useModelsStore } from '~/common/stores/llms/store-llms'; +import { useDefaultLLMs } from '~/common/stores/llms/llms.hooks'; import type { FormRadioOption } from './FormRadioControl'; import { useFormRadio } from './useFormRadio'; @@ -13,15 +12,7 @@ type LlmType = 'chat' | 'fast'; export function useFormRadioLlmType(label: string = 'Model', initialModelType: LlmType = 'fast'): [DLLM | null, React.JSX.Element | null] { // external state - const { chatLLM, fastLLM } = useModelsStore(useShallow(state => { - const { chatLLMId, fastLLMId } = state; - const chatLLM = chatLLMId ? state.llms.find(llm => llm.id === chatLLMId) ?? null : null; - const fastLLM = fastLLMId ? state.llms.find(llm => llm.id === fastLLMId) ?? null : null; - return { - chatLLM, - fastLLM, - }; - })); + const { chatLLM, fastLLM } = useDefaultLLMs(); const hidden = !chatLLM || !fastLLM || chatLLM === fastLLM; diff --git a/src/common/components/forms/useLLMSelect.tsx b/src/common/components/forms/useLLMSelect.tsx index 579951cfd..38442e3d8 100644 --- a/src/common/components/forms/useLLMSelect.tsx +++ b/src/common/components/forms/useLLMSelect.tsx @@ -1,5 +1,4 @@ import * as React from 'react'; -import { useShallow } from 'zustand/react/shallow'; import type { SxProps } from '@mui/joy/styles/types'; import { FormControl, ListDivider, ListItemDecorator, Option, Select, SvgIconProps } from '@mui/joy'; @@ -8,18 +7,19 @@ import type { IModelVendor } from '~/modules/llms/vendors/IModelVendor'; import { findModelVendor } from '~/modules/llms/vendors/vendors.registry'; import type { DLLM, DLLMId } from '~/common/stores/llms/llms.types'; -import { useModelsStore } from '~/common/stores/llms/store-llms'; +import { getChatLLMId } from '~/common/stores/llms/store-llms'; +import { useNonHiddenLLMs } from '~/common/stores/llms/llms.hooks'; import { FormLabelStart } from './FormLabelStart'; /*export function useLLMSelectGlobalState(): [DLLMId | null, (llmId: DLLMId | null) => void] { - return useModelsStore(useShallow(state => [state.chatLLMId, state.setChatLLMId])); + return ...(useShallow(state => [state.chatLLMId, state.setChatLLMId])); }*/ export function useLLMSelectLocalState(initFromGlobal: boolean): [DLLMId | null, (llmId: DLLMId | null) => void] { return React.useState(initFromGlobal ? () => { - return useModelsStore.getState().chatLLMId; + return getChatLLMId(); } : null); } @@ -51,9 +51,7 @@ export function useLLMSelect( ): [DLLM | null, React.JSX.Element | null, React.FunctionComponent | undefined] { // external state - const _filteredLLMs = useModelsStore(useShallow(state => - state.llms.filter(llm => !llm.hidden || (chatLLMId && llm.id === chatLLMId)), - )); + const _filteredLLMs = useNonHiddenLLMs(); // derived state const noIcons = false; //smaller; diff --git a/src/common/layout/optima/DesktopNav.tsx b/src/common/layout/optima/DesktopNav.tsx index b638478fa..0e9a2018f 100644 --- a/src/common/layout/optima/DesktopNav.tsx +++ b/src/common/layout/optima/DesktopNav.tsx @@ -6,11 +6,10 @@ import { Divider, Dropdown, ListItemDecorator, Menu, MenuButton, MenuItem, Toolt import MenuIcon from '@mui/icons-material/Menu'; import MoreHorizIcon from '@mui/icons-material/MoreHoriz'; -import { useModelsStore } from '~/common/stores/llms/store-llms'; - import { AgiSquircleIcon } from '~/common/components/icons/AgiSquircleIcon'; import { checkDivider, checkVisibileIcon, NavItemApp, navItems } from '~/common/app.nav'; import { themeZIndexDesktopNav } from '~/common/app.theme'; +import { useHasLLMs } from '~/common/stores/llms/llms.hooks'; import { BringTheLove } from './components/BringTheLove'; import { DesktopNavGroupBox, DesktopNavIcon, navItemClasses } from './components/DesktopNavIcon'; @@ -38,7 +37,7 @@ export function DesktopNav(props: { component: React.ElementType, currentApp?: N // external state const isDrawerOpen = useOptimaDrawerOpen(); const { showModels, showPreferences } = useOptimaModelsModalsState(); - const noLLMs = useModelsStore(state => !state.llms.length); + const noLLMs = !useHasLLMs(); // show/hide the pane when clicking on the logo diff --git a/src/common/logic/autoconf.ts b/src/common/logic/autoconf.ts index b647de88a..21006366d 100644 --- a/src/common/logic/autoconf.ts +++ b/src/common/logic/autoconf.ts @@ -7,7 +7,7 @@ import { getBackendCapabilities } from '~/modules/backend/store-backend-capabili import { llmsUpdateModelsForServiceOrThrow } from '~/modules/llms/llm.client'; import type { DModelsService } from '~/common/stores/llms/modelsservice.types'; -import { useModelsStore } from '~/common/stores/llms/store-llms'; +import { llmsStoreState } from '~/common/stores/llms/store-llms'; interface AutoConfStore { @@ -56,14 +56,15 @@ const autoConfVanillaStore = createVanillaStore()(persist((_set, .then(async () => { // find the first service for this vendor - const { sources: modelsServices, addService } = useModelsStore.getState(); + const { sources: modelsServices, addService } = llmsStoreState(); let service: DModelsService; const firstServiceForVendor = modelsServices.find(s => s.vId === vendor.id); if (!firstServiceForVendor) { // create and append the model service, assuming the backend configuration will be successful service = createModelsServiceForVendor(vendor.id, modelsServices); addService(service); - service = useModelsStore.getState().sources.find(_s => _s.id === service.id)!; + // re-find it now what's added + service = llmsStoreState().sources.find(_s => _s.id === service.id)!; } else service = firstServiceForVendor; diff --git a/src/common/stores/llms/llms.hooks.ts b/src/common/stores/llms/llms.hooks.ts index d4cba7aa6..15127f946 100644 --- a/src/common/stores/llms/llms.hooks.ts +++ b/src/common/stores/llms/llms.hooks.ts @@ -1,4 +1,6 @@ -import type { DLLM } from './llms.types'; +import { useShallow } from 'zustand/react/shallow'; + +import type { DLLM, DLLMId } from './llms.types'; import { useModelsStore } from './store-llms'; @@ -11,6 +13,48 @@ export function useChatLLM(): { chatLLM: DLLM | null } { return { chatLLM }; } +export function useLLM(llmId: DLLMId): DLLM | null { + return useModelsStore(state => state.llms.find(llm => llm.id === llmId) ?? null); +} + +export function useDefaultLLMIDs(): { chatLLMId: DLLMId | null; fastLLMId: DLLMId | null; funcLLMId: DLLMId | null; } { + return useModelsStore(useShallow(state => ({ + chatLLMId: state.chatLLMId, + fastLLMId: state.fastLLMId, + funcLLMId: state.funcLLMId, + }))); +} + +export function useDefaultLLMs(): { chatLLM: DLLM | null; fastLLM: DLLM | null; funcLLM: DLLM | null } { + return useModelsStore(useShallow(state => { + const { chatLLMId, fastLLMId, funcLLMId } = state; + const chatLLM = chatLLMId ? state.llms.find(llm => llm.id === chatLLMId) ?? null : null; + const fastLLM = fastLLMId ? state.llms.find(llm => llm.id === fastLLMId) ?? null : null; + const funcLLM = funcLLMId ? state.llms.find(llm => llm.id === funcLLMId) ?? null : null; + return { chatLLM, fastLLM, funcLLM }; + })); +} + +export function useFilteredLLMs(filterId: false | DLLMId): DLLM[] { + return useModelsStore(useShallow( + state => !filterId ? state.llms : state.llms.filter(llm => llm.sId === filterId), + )); +} + +export function useNonHiddenLLMs(): DLLM[] { + return useModelsStore(useShallow( + ({ llms, chatLLMId }) => llms.filter(llm => !llm.hidden || (chatLLMId && llm.id === chatLLMId)), + )); +} + +export function useLLMsCount(): number { + return useModelsStore(state => state.llms.length); +} + +export function useHasLLMs(): boolean { + return useModelsStore(state => !!state.llms.length); +} + export function useModelsServices() { return useModelsStore(state => state.sources); } \ No newline at end of file diff --git a/src/common/stores/llms/store-llms.ts b/src/common/stores/llms/store-llms.ts index dd386feb5..938650614 100644 --- a/src/common/stores/llms/store-llms.ts +++ b/src/common/stores/llms/store-llms.ts @@ -43,7 +43,7 @@ interface LlmsActions { setFuncLLMId: (id: DLLMId | null) => void; // special - setOpenRoutersKey: (key: string) => void; + setOpenRouterKey: (key: string) => void; } @@ -163,7 +163,7 @@ export const useModelsStore = create()(persist( ), })), - setOpenRoutersKey: (key: string) => + setOpenRouterKey: (key: string) => set(state => { const firstOpenRouterService = state.sources.find(s => s.vId === 'openrouter'); return !firstOpenRouterService ? state : { @@ -270,6 +270,10 @@ export function getFastLLMId(): DLLMId | null { return llmsStoreState().fastLLMId; } +export function getFuncLLMId(): DLLMId | null { + return llmsStoreState().funcLLMId; +} + export function llmsStoreState(): LlmsState & LlmsActions { return useModelsStore.getState(); } @@ -321,7 +325,7 @@ export function getDiverseTopLlmIds(count: number, requireElo: boolean, fallback } export function getLLMsDebugInfo() { - const { llms, sources, chatLLMId, fastLLMId, funcLLMId } = useModelsStore.getState(); + const { llms, sources, chatLLMId, fastLLMId, funcLLMId } = llmsStoreState(); return { services: sources.length, llmsCount: llms.length, chatId: chatLLMId, fastId: fastLLMId, funcId: funcLLMId }; } diff --git a/src/common/stores/metrics/store-metrics.ts b/src/common/stores/metrics/store-metrics.ts index 69b2beb88..e99b7ed90 100644 --- a/src/common/stores/metrics/store-metrics.ts +++ b/src/common/stores/metrics/store-metrics.ts @@ -14,7 +14,7 @@ // interface MetricsActions { // } // -// export const useModelsStore = create()(persist( +// export const useMetricsStore = create()(persist( // (set) => ({ // // // initial state diff --git a/src/modules/aifn/autosuggestions/autoSuggestions.ts b/src/modules/aifn/autosuggestions/autoSuggestions.ts index 27e3a3484..2a85a777f 100644 --- a/src/modules/aifn/autosuggestions/autoSuggestions.ts +++ b/src/modules/aifn/autosuggestions/autoSuggestions.ts @@ -4,7 +4,7 @@ import { ConversationsManager } from '~/common/chat-overlay/ConversationsManager import { DLLMId, LLM_IF_OAI_Fn } from '~/common/stores/llms/llms.types'; import { DMessage, messageFragmentsReduceText } from '~/common/stores/chat/chat.message'; import { createErrorContentFragment, createPlaceholderMetaFragment, createTextContentFragment } from '~/common/stores/chat/chat.fragments'; -import { findLLMOrThrow, useModelsStore } from '~/common/stores/llms/store-llms'; +import { findLLMOrThrow, getFuncLLMId } from '~/common/stores/llms/store-llms'; import { marshallWrapText } from '~/common/stores/chat/chat.tokens'; import { useChatStore } from '~/common/stores/chat/store-chats'; @@ -156,7 +156,7 @@ function validateFunctionLLMId(funcLLMId: DLLMId | null): DLLMId | null { } // if not provided, or provided but not a function llm, then use the default - return useModelsStore.getState().funcLLMId; + return getFuncLLMId(); } diff --git a/src/modules/aifn/summarize/ContentReducer.tsx b/src/modules/aifn/summarize/ContentReducer.tsx index 943b6dfe8..60cebf09c 100644 --- a/src/modules/aifn/summarize/ContentReducer.tsx +++ b/src/modules/aifn/summarize/ContentReducer.tsx @@ -1,10 +1,8 @@ import * as React from 'react'; -import { useShallow } from 'zustand/react/shallow'; import { Alert, Box, Button, CircularProgress, Divider, FormControl, Option, Select, Slider, Stack, Textarea, Typography } from '@mui/joy'; import type { DLLM, DLLMId } from '~/common/stores/llms/llms.types'; -import { useModelsStore } from '~/common/stores/llms/store-llms'; import { TokenBadgeMemo } from '../../../apps/chat/components/composer/tokens/TokenBadge'; @@ -12,6 +10,7 @@ import { FormLabelStart } from '~/common/components/forms/FormLabelStart'; import { GoodModal } from '~/common/components/GoodModal'; import { Section } from '~/common/components/Section'; import { lineHeightTextareaMd } from '~/common/app.theme'; +import { useDefaultLLMIDs, useNonHiddenLLMs } from '~/common/stores/llms/llms.hooks'; import { summerizeToFitContextBudget } from './summerize'; @@ -39,10 +38,8 @@ export function ContentReducer(props: { }) { // external state - const { llms, fastLLMId } = useModelsStore(useShallow(state => ({ - llms: state.llms, // probably relying on the stability of this - fastLLMId: state.fastLLMId, - }))); + const llms = useNonHiddenLLMs(); + const { fastLLMId } = useDefaultLLMIDs(); // state const [reducerModelId, setReducerModelId] = React.useState(fastLLMId); diff --git a/src/modules/llms/llm.client.ts b/src/modules/llms/llm.client.ts index 85ae3374c..0bda7eccf 100644 --- a/src/modules/llms/llm.client.ts +++ b/src/modules/llms/llm.client.ts @@ -6,7 +6,7 @@ import type { OpenAIWire_Tools } from '~/modules/aix/server/dispatch/wiretypes/o import type { DModelsService, DModelsServiceId } from '~/common/stores/llms/modelsservice.types'; import { DLLM, DLLMId, LLM_IF_OAI_Chat, LLM_IF_OAI_Fn } from '~/common/stores/llms/llms.types'; -import { findLLMOrThrow, useModelsStore } from '~/common/stores/llms/store-llms'; +import { findLLMOrThrow, llmsStoreActions } from '~/common/stores/llms/store-llms'; import { isModelPriceFree } from '~/common/stores/llms/llms.pricing'; import type { ChatStreamingInputSchema } from './server/llm.server.streaming'; @@ -54,7 +54,7 @@ export async function llmsUpdateModelsForServiceOrThrow(serviceId: DModelsServic const data = await vendor.rpcUpdateModelsOrThrow(transportAccess); // update the global models store - useModelsStore.getState().setLLMs( + llmsStoreActions().setLLMs( data.models.map(model => _createDLLMFromModelDescription(model, service)), service.id, true, diff --git a/src/modules/llms/models-modal/LLMOptionsModal.tsx b/src/modules/llms/models-modal/LLMOptionsModal.tsx index 1077f9729..93c186f25 100644 --- a/src/modules/llms/models-modal/LLMOptionsModal.tsx +++ b/src/modules/llms/models-modal/LLMOptionsModal.tsx @@ -1,6 +1,5 @@ import * as React from 'react'; import TimeAgo from 'react-timeago'; -import { useShallow } from 'zustand/react/shallow'; import { Box, Button, ButtonGroup, Divider, FormControl, Input, Switch, Tooltip, Typography } from '@mui/joy'; import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline'; @@ -11,14 +10,15 @@ import type { DChatGeneratePricing } from '~/common/stores/llms/llms.pricing'; import type { DLLMId } from '~/common/stores/llms/llms.types'; import { FormLabelStart } from '~/common/components/forms/FormLabelStart'; import { GoodModal } from '~/common/components/GoodModal'; -import { useModelsStore } from '~/common/stores/llms/store-llms'; +import { llmsStoreActions } from '~/common/stores/llms/store-llms'; +import { useDefaultLLMIDs, useLLM } from '~/common/stores/llms/llms.hooks'; import { findModelVendor } from '../vendors/vendors.registry'; function VendorLLMOptionsComponent(props: { llmId: DLLMId }) { // get LLM (warning: this will refresh all children components on every change of any LLM field) - const llm = useModelsStore(state => state.llms.find(llm => llm.id === props.llmId)); + const llm = useLLM(props.llmId); if (!llm) return 'Options issue: LLM not found for id ' + props.llmId; @@ -69,27 +69,16 @@ export function LLMOptionsModal(props: { id: DLLMId, onClose: () => void }) { const [showDetails, setShowDetails] = React.useState(false); // external state - const { - llm, - removeLLM, updateLLM, - isChatLLM, setChatLLMId, - isFastLLM, setFastLLMId, - isFuncLLM, setFuncLLMId, - } = useModelsStore(useShallow(state => ({ - llm: state.llms.find(llm => llm.id === props.id), - removeLLM: state.removeLLM, - updateLLM: state.updateLLM, - isChatLLM: state.chatLLMId === props.id, - isFastLLM: state.fastLLMId === props.id, - isFuncLLM: state.funcLLMId === props.id, - setChatLLMId: state.setChatLLMId, - setFastLLMId: state.setFastLLMId, - setFuncLLMId: state.setFuncLLMId, - }))); + const llm = useLLM(props.id); + const { chatLLMId, fastLLMId, funcLLMId } = useDefaultLLMIDs(); + const { removeLLM, updateLLM, setChatLLMId, setFastLLMId, setFuncLLMId } = llmsStoreActions(); if (!llm) return <>Options issue: LLM not found for id {props.id}; + const isChatLLM = chatLLMId === props.id; + const isFastLLM = fastLLMId === props.id; + const isFuncLLM = funcLLMId === props.id; const handleLlmLabelSet = (event: React.ChangeEvent) => updateLLM(llm.id, { label: event.target.value || '' }); diff --git a/src/modules/llms/models-modal/ModelsList.tsx b/src/modules/llms/models-modal/ModelsList.tsx index ebc9d1e9e..2d037d95d 100644 --- a/src/modules/llms/models-modal/ModelsList.tsx +++ b/src/modules/llms/models-modal/ModelsList.tsx @@ -1,5 +1,4 @@ import * as React from 'react'; -import { useShallow } from 'zustand/react/shallow'; import type { SxProps } from '@mui/joy/styles/types'; import { Box, Chip, IconButton, List, ListItem, ListItemButton, Typography } from '@mui/joy'; @@ -11,7 +10,8 @@ import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined'; import type { DLLM, DLLMId } from '~/common/stores/llms/llms.types'; import type { DModelsServiceId } from '~/common/stores/llms/modelsservice.types'; import { GoodTooltip } from '~/common/components/GoodTooltip'; -import { findModelsServiceOrNull, useModelsStore } from '~/common/stores/llms/store-llms'; +import { findModelsServiceOrNull, llmsStoreActions } from '~/common/stores/llms/store-llms'; +import { useDefaultLLMIDs, useFilteredLLMs } from '~/common/stores/llms/llms.hooks'; import { IModelVendor } from '../vendors/IModelVendor'; import { findModelVendor } from '../vendors/vendors.registry'; @@ -150,16 +150,9 @@ export function ModelsList(props: { }) { // external state - const { chatLLMId, fastLLMId, funcLLMId, updateLLM } = useModelsStore(useShallow(state => ({ - chatLLMId: state.chatLLMId, - fastLLMId: state.fastLLMId, - funcLLMId: state.funcLLMId, - updateLLM: state.updateLLM, - }))); - const llms = useModelsStore(useShallow(state => - // note: we don't put this together with the former, to avoid going 1-level too deep in the shallow comparison - state.llms.filter(llm => !props.filterServiceId || llm.sId === props.filterServiceId), - )); + const { updateLLM } = llmsStoreActions(); + const { chatLLMId, fastLLMId, funcLLMId } = useDefaultLLMIDs(); + const llms = useFilteredLLMs(props.filterServiceId === null ? false : props.filterServiceId); const { onOpenLLMOptions } = props; diff --git a/src/modules/llms/models-modal/ModelsModal.tsx b/src/modules/llms/models-modal/ModelsModal.tsx index 7fd5fb303..9fd6d033d 100644 --- a/src/modules/llms/models-modal/ModelsModal.tsx +++ b/src/modules/llms/models-modal/ModelsModal.tsx @@ -1,13 +1,13 @@ import * as React from 'react'; -import { useShallow } from 'zustand/react/shallow'; import { Box, Checkbox, Divider } from '@mui/joy'; import type { DModelsService, DModelsServiceId } from '~/common/stores/llms/modelsservice.types'; import { GoodModal } from '~/common/components/GoodModal'; -import { llmsStoreState, useModelsStore } from '~/common/stores/llms/store-llms'; +import { llmsStoreState } from '~/common/stores/llms/store-llms'; import { optimaActions, optimaOpenModels, useOptimaModelsModalsState } from '~/common/layout/optima/useOptima'; import { runWhenIdle } from '~/common/util/pwaUtils'; +import { useLLMsCount, useModelsServices } from '~/common/stores/llms/llms.hooks'; import { LLMOptionsModal } from './LLMOptionsModal'; import { ModelsList } from './ModelsList'; @@ -32,10 +32,8 @@ export function ModelsModal(props: { suspendAutoModelsSetup?: boolean }) { // external state const { showModels, showModelOptions } = useOptimaModelsModalsState(); - const { modelsServices, llmCount } = useModelsStore(useShallow(state => ({ - modelsServices: state.sources, - llmCount: state.llms.length, - }))); + const modelsServices = useModelsServices(); + const llmCount = useLLMsCount(); // auto-select the first service - note: we could use a useEffect() here, but this is more efficient // also note that state-persistence is unneeded diff --git a/src/modules/llms/vendors/openai/OpenAILLMOptions.tsx b/src/modules/llms/vendors/openai/OpenAILLMOptions.tsx index 1bd4c032d..45abb77ae 100644 --- a/src/modules/llms/vendors/openai/OpenAILLMOptions.tsx +++ b/src/modules/llms/vendors/openai/OpenAILLMOptions.tsx @@ -7,7 +7,7 @@ import type { DLLM } from '~/common/stores/llms/llms.types'; import { FormSliderControl } from '~/common/components/forms/FormSliderControl'; import { InlineError } from '~/common/components/InlineError'; -import { useModelsStore } from '~/common/stores/llms/store-llms'; +import { llmsStoreActions } from '~/common/stores/llms/store-llms'; import { DOpenAILLMOptions, FALLBACK_LLM_RESPONSE_TOKENS, FALLBACK_LLM_TEMPERATURE } from './openai.vendor'; @@ -27,7 +27,7 @@ export function OpenAILLMOptions(props: { llm: DLLM }) { // derived state const { id: llmId, maxOutputTokens, options } = props.llm; const { llmResponseTokens, llmTemperature } = normalizeOpenAIOptions(options); - const { updateLLMOptions } = useModelsStore.getState(); + const { updateLLMOptions } = llmsStoreActions(); // state (here because the initial state depends on props) const [overheat, setOverheat] = React.useState(llmTemperature > 1); diff --git a/src/modules/llms/vendors/openrouter/OpenRouterServiceSetup.tsx b/src/modules/llms/vendors/openrouter/OpenRouterServiceSetup.tsx index ad56a623a..d17b9dc3e 100644 --- a/src/modules/llms/vendors/openrouter/OpenRouterServiceSetup.tsx +++ b/src/modules/llms/vendors/openrouter/OpenRouterServiceSetup.tsx @@ -11,7 +11,7 @@ import { InlineError } from '~/common/components/InlineError'; import { Link } from '~/common/components/Link'; import { SetupFormRefetchButton } from '~/common/components/forms/SetupFormRefetchButton'; import { getCallbackUrl } from '~/common/app.routes'; -import { useModelsStore } from '~/common/stores/llms/store-llms'; +import { llmsStoreState } from '~/common/stores/llms/store-llms'; import { useLlmUpdateModels } from '../../llm.client.hooks'; import { useServiceSetup } from '../useServiceSetup'; @@ -48,7 +48,7 @@ export function OpenRouterServiceSetup(props: { serviceId: DModelsServiceId }) { const handleRemoveNonFreeLLMs = () => { // A bit of a hack - const { llms, removeLLM } = useModelsStore.getState(); + const { llms, removeLLM } = llmsStoreState(); llms .filter(llm => llm.sId === props.serviceId) .filter(llm => llm.pricing?.chat?._isFree === false) @@ -57,7 +57,7 @@ export function OpenRouterServiceSetup(props: { serviceId: DModelsServiceId }) { }; const handleSetVisibilityAll = React.useCallback((visible: boolean) => { - const { llms, updateLLM } = useModelsStore.getState(); + const { llms, updateLLM } = llmsStoreState(); llms .filter(llm => llm.sId === props.serviceId) .forEach(llm => updateLLM(llm.id, { hidden: !visible })); diff --git a/src/modules/t2i/t2i.client.ts b/src/modules/t2i/t2i.client.ts index 4f425ef57..f9f05665c 100644 --- a/src/modules/t2i/t2i.client.ts +++ b/src/modules/t2i/t2i.client.ts @@ -11,7 +11,7 @@ import type { DLLM } from '~/common/stores/llms/llms.types'; import type { DModelsService, DModelsServiceId } from '~/common/stores/llms/modelsservice.types'; import { createDMessageDataRefDBlob, createImageContentFragment, DMessageContentFragment } from '~/common/stores/chat/chat.fragments'; import { shallowEquals } from '~/common/util/hooks/useShallowObject'; -import { useModelsStore } from '~/common/stores/llms/store-llms'; +import { llmsStoreState, useModelsStore } from '~/common/stores/llms/store-llms'; import type { T2iCreateImageOutput } from './t2i.server'; import { openAIGenerateImagesOrThrow } from './dalle/openaiGenerateImages'; @@ -81,7 +81,7 @@ export function getActiveTextToImageProviderOrThrow() { throw new Error('No TextToImage Provider selected'); // [immediate] get all providers - const { llms, sources: modelsServices } = useModelsStore.getState(); + const { llms, sources: modelsServices } = llmsStoreState(); const openAIModelsServiceIDs = getLlmsModelServices(llms, modelsServices); const providers = getTextToImageProviders(openAIModelsServiceIDs, !!useProdiaStore.getState().prodiaModelId); diff --git a/src/modules/trade/trade.client.ts b/src/modules/trade/trade.client.ts index fc147706f..c4f7f8713 100644 --- a/src/modules/trade/trade.client.ts +++ b/src/modules/trade/trade.client.ts @@ -6,12 +6,12 @@ import { Brand } from '~/common/app.config'; import { DataAtRestV1 } from '~/common/stores/chat/chats.converters'; import { capitalizeFirstLetter } from '~/common/util/textUtils'; import { conversationTitle, DConversation } from '~/common/stores/chat/chat.conversation'; +import { llmsStoreState } from '~/common/stores/llms/store-llms'; import { messageFragmentsReduceText } from '~/common/stores/chat/chat.message'; import { prettyBaseModel } from '~/common/util/modelUtils'; import { prettyTimestampForFilenames } from '~/common/util/timeUtils'; import { useChatStore } from '~/common/stores/chat/store-chats'; import { useFolderStore } from '~/common/state/store-folders'; -import { useModelsStore } from '~/common/stores/llms/store-llms'; import type { ImportedOutcome } from './ImportOutcomeModal'; @@ -124,7 +124,7 @@ export async function downloadAllJsonV1B() { const { folders, enableFolders } = useFolderStore.getState(); const payload = DataAtRestV1.formatAllToJsonV1B( useChatStore.getState().conversations, - useModelsStore.getState().sources, + llmsStoreState().sources, folders, enableFolders, ); const json = JSON.stringify(payload);