diff --git a/extensions/engine-management-extension/models/anthropic.json b/extensions/engine-management-extension/models/anthropic.json index d35ba4c22e..46b5893d17 100644 --- a/extensions/engine-management-extension/models/anthropic.json +++ b/extensions/engine-management-extension/models/anthropic.json @@ -8,7 +8,7 @@ "inference_params": { "max_tokens": 4096, "temperature": 0.7, - "stream": false + "stream": true }, "engine": "anthropic" }, @@ -21,7 +21,7 @@ "inference_params": { "max_tokens": 8192, "temperature": 0.7, - "stream": false + "stream": true }, "engine": "anthropic" }, diff --git a/web/containers/Layout/BottomPanel/SystemMonitor/TableActiveModel/index.tsx b/web/containers/Layout/BottomPanel/SystemMonitor/TableActiveModel/index.tsx index 06eebea923..36cdd317fa 100644 --- a/web/containers/Layout/BottomPanel/SystemMonitor/TableActiveModel/index.tsx +++ b/web/containers/Layout/BottomPanel/SystemMonitor/TableActiveModel/index.tsx @@ -1,19 +1,20 @@ import { Tooltip, Button, Badge } from '@janhq/joi' -import { useAtom, useAtomValue } from 'jotai' +import { useAtom } from 'jotai' import { useActiveModel } from '@/hooks/useActiveModel' +import { useGetEngines } from '@/hooks/useEngineManagement' + import { toGibibytes } from '@/utils/converter' import { isLocalEngine } from '@/utils/modelEngine' -import { installedEnginesAtom } from '@/helpers/atoms/Engines.atom' import { serverEnabledAtom } from '@/helpers/atoms/LocalServer.atom' const TableActiveModel = () => { const { activeModel, stateModel, stopModel } = useActiveModel() - const engines = useAtomValue(installedEnginesAtom) + const { engines } = useGetEngines() const [serverEnabled, setServerEnabled] = useAtom(serverEnabledAtom) diff --git a/web/containers/ModelDropdown/index.tsx b/web/containers/ModelDropdown/index.tsx index 04e350c719..c774a0813c 100644 --- a/web/containers/ModelDropdown/index.tsx +++ b/web/containers/ModelDropdown/index.tsx @@ -31,6 +31,7 @@ import SetupRemoteModel from '@/containers/SetupRemoteModel' import { useCreateNewThread } from '@/hooks/useCreateNewThread' import useDownloadModel from '@/hooks/useDownloadModel' import { modelDownloadStateAtom } from '@/hooks/useDownloadState' +import { useGetEngines } from '@/hooks/useEngineManagement' import useRecommendedModel from '@/hooks/useRecommendedModel' @@ -42,7 +43,6 @@ import { manualRecommendationModel } from '@/utils/model' import { getLogoEngine } from '@/utils/modelEngine' import { activeAssistantAtom } from '@/helpers/atoms/Assistant.atom' -import { installedEnginesAtom } from '@/helpers/atoms/Engines.atom' import { configuredModelsAtom, getDownloadingModelAtom, @@ -86,7 +86,7 @@ const ModelDropdown = ({ null ) - const engines = useAtomValue(installedEnginesAtom) + const { engines } = useGetEngines() const downloadStates = useAtomValue(modelDownloadStateAtom) const setThreadModelParams = useSetAtom(setThreadModelParamsAtom) diff --git a/web/containers/Providers/DataLoader.tsx b/web/containers/Providers/DataLoader.tsx index 01093e4b21..832e47d1a1 100644 --- a/web/containers/Providers/DataLoader.tsx +++ b/web/containers/Providers/DataLoader.tsx @@ -2,11 +2,18 @@ import { Fragment, useEffect } from 'react' -import { AppConfiguration, getUserHomePath } from '@janhq/core' +import { + AppConfiguration, + EngineEvent, + events, + getUserHomePath, +} from '@janhq/core' import { useSetAtom } from 'jotai' +import { useDebouncedCallback } from 'use-debounce' + import useAssistants from '@/hooks/useAssistants' -import useEngines from '@/hooks/useEngines' +import { useGetEngines } from '@/hooks/useEngineManagement' import useGetSystemResources from '@/hooks/useGetSystemResources' import useModels from '@/hooks/useModels' import useThreads from '@/hooks/useThreads' @@ -26,7 +33,7 @@ const DataLoader: React.FC = () => { const setJanDefaultDataFolder = useSetAtom(defaultJanDataFolderAtom) const setJanSettingScreen = useSetAtom(janSettingScreenAtom) const { getData: loadModels } = useModels() - const { getData: loadEngines } = useEngines() + const { mutate } = useGetEngines() useThreads() useAssistants() @@ -35,9 +42,19 @@ const DataLoader: React.FC = () => { useEffect(() => { // Load data once loadModels() - loadEngines() // eslint-disable-next-line react-hooks/exhaustive-deps }, []) + const reloadData = useDebouncedCallback(() => { + mutate() + }, 300) + + useEffect(() => { + events.on(EngineEvent.OnEngineUpdate, reloadData) + return () => { + // Remove listener on unmount + events.off(EngineEvent.OnEngineUpdate, reloadData) + } + }, [reloadData]) useEffect(() => { window.core?.api diff --git a/web/containers/Providers/ModelHandler.tsx b/web/containers/Providers/ModelHandler.tsx index 1c60eefd55..cc7a0da807 100644 --- a/web/containers/Providers/ModelHandler.tsx +++ b/web/containers/Providers/ModelHandler.tsx @@ -23,6 +23,8 @@ import { ulid } from 'ulidx' import { activeModelAtom, stateModelAtom } from '@/hooks/useActiveModel' +import { useGetEngines } from '@/hooks/useEngineManagement' + import { isLocalEngine } from '@/utils/modelEngine' import { extensionManager } from '@/extension' @@ -34,7 +36,6 @@ import { deleteMessageAtom, subscribedGeneratingMessageAtom, } from '@/helpers/atoms/ChatMessage.atom' -import { installedEnginesAtom } from '@/helpers/atoms/Engines.atom' import { downloadedModelsAtom } from '@/helpers/atoms/Model.atom' import { updateThreadWaitingForResponseAtom, @@ -75,7 +76,7 @@ export default function ModelHandler() { const activeModelParams = useAtomValue(getActiveThreadModelParamsAtom) const activeModelParamsRef = useRef(activeModelParams) const setTokenSpeed = useSetAtom(tokenSpeedAtom) - const engines = useAtomValue(installedEnginesAtom) + const { engines } = useGetEngines() useEffect(() => { activeThreadRef.current = activeThread diff --git a/web/helpers/atoms/Engines.atom.ts b/web/helpers/atoms/Engines.atom.ts deleted file mode 100644 index b1b09426a3..0000000000 --- a/web/helpers/atoms/Engines.atom.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Engines } from '@janhq/core' -import { atom } from 'jotai' - -/** - * Store all of the installed engines including local and remote engines - */ -export const installedEnginesAtom = atom() diff --git a/web/hooks/useEngines.ts b/web/hooks/useEngines.ts deleted file mode 100644 index f910394e3f..0000000000 --- a/web/hooks/useEngines.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { useCallback, useEffect } from 'react' - -import { - ExtensionTypeEnum, - events, - EngineEvent, - EngineManagementExtension, - Engines, -} from '@janhq/core' - -import { useSetAtom } from 'jotai' - -import { useDebouncedCallback } from 'use-debounce' - -import { extensionManager } from '@/extension' - -import { installedEnginesAtom } from '@/helpers/atoms/Engines.atom' - -/** - * useModels hook - Handles the state of models - * It fetches the downloaded models, configured models and default model from Model Extension - * and updates the atoms accordingly. - */ -const useEngines = () => { - const setInstalledEngines = useSetAtom(installedEnginesAtom) - - const getData = useCallback(() => { - getEngines().then(setInstalledEngines) - }, [setInstalledEngines]) - - const reloadData = useDebouncedCallback(() => getData(), 300) - - const getEngines = async (): Promise => - extensionManager - .get(ExtensionTypeEnum.Engine) - ?.getEngines() - .catch(() => ({}) as Engines) ?? ({} as Engines) - - useEffect(() => { - // Listen for engine updates - events.on(EngineEvent.OnEngineUpdate, reloadData) - return () => { - // Remove listener on unmount - events.off(EngineEvent.OnEngineUpdate, reloadData) - } - }, [reloadData]) - - return { - getData, - } -} - -export default useEngines diff --git a/web/hooks/useRecommendedModel.ts b/web/hooks/useRecommendedModel.ts index 64376f7a17..4107087f8d 100644 --- a/web/hooks/useRecommendedModel.ts +++ b/web/hooks/useRecommendedModel.ts @@ -6,8 +6,9 @@ import { atom, useAtomValue } from 'jotai' import { activeModelAtom } from './useActiveModel' +import { useGetEngines } from './useEngineManagement' + import { activeAssistantAtom } from '@/helpers/atoms/Assistant.atom' -import { installedEnginesAtom } from '@/helpers/atoms/Engines.atom' import { downloadedModelsAtom } from '@/helpers/atoms/Model.atom' import { activeThreadAtom } from '@/helpers/atoms/Thread.atom' @@ -31,7 +32,7 @@ export default function useRecommendedModel() { const activeThread = useAtomValue(activeThreadAtom) const downloadedModels = useAtomValue(downloadedModelsAtom) const activeAssistant = useAtomValue(activeAssistantAtom) - const engines = useAtomValue(installedEnginesAtom) + const { engines } = useGetEngines() const getAndSortDownloadedModels = useCallback(async (): Promise => { const models = downloadedModels.sort((a, b) => diff --git a/web/hooks/useStarterScreen.ts b/web/hooks/useStarterScreen.ts index 200e645dc0..f0bc7eeda8 100644 --- a/web/hooks/useStarterScreen.ts +++ b/web/hooks/useStarterScreen.ts @@ -6,7 +6,8 @@ import { useAtomValue } from 'jotai' import { isLocalEngine } from '@/utils/modelEngine' -import { installedEnginesAtom } from '@/helpers/atoms/Engines.atom' +import { useGetEngines } from './useEngineManagement' + import { downloadedModelsAtom } from '@/helpers/atoms/Model.atom' import { threadsAtom } from '@/helpers/atoms/Thread.atom' @@ -14,7 +15,7 @@ export function useStarterScreen() { const downloadedModels = useAtomValue(downloadedModelsAtom) const threads = useAtomValue(threadsAtom) - const engines = useAtomValue(installedEnginesAtom) + const { engines } = useGetEngines() const remoteEngines = engines && diff --git a/web/screens/Hub/ModelList/index.tsx b/web/screens/Hub/ModelList/index.tsx index 0984a3a017..4c6c7d993a 100644 --- a/web/screens/Hub/ModelList/index.tsx +++ b/web/screens/Hub/ModelList/index.tsx @@ -4,9 +4,10 @@ import { Model } from '@janhq/core' import { useAtomValue } from 'jotai' +import { useGetEngines } from '@/hooks/useEngineManagement' + import ModelItem from '@/screens/Hub/ModelList/ModelItem' -import { installedEnginesAtom } from '@/helpers/atoms/Engines.atom' import { downloadedModelsAtom } from '@/helpers/atoms/Model.atom' type Props = { @@ -15,7 +16,7 @@ type Props = { const ModelList = ({ models }: Props) => { const downloadedModels = useAtomValue(downloadedModelsAtom) - const engines = useAtomValue(installedEnginesAtom) + const { engines } = useGetEngines() const sortedModels: Model[] = useMemo(() => { const featuredModels: Model[] = [] const remoteModels: Model[] = [] diff --git a/web/screens/Settings/Engines/index.tsx b/web/screens/Settings/Engines/index.tsx index a79ba5be68..4ad1559395 100644 --- a/web/screens/Settings/Engines/index.tsx +++ b/web/screens/Settings/Engines/index.tsx @@ -4,16 +4,16 @@ import { InferenceEngine } from '@janhq/core' import { ScrollArea } from '@janhq/joi' import { useAtomValue } from 'jotai' +import { useGetEngines } from '@/hooks/useEngineManagement' + import { isLocalEngine } from '@/utils/modelEngine' import LocalEngineItems from './LocalEngineItem' import ModalAddRemoteEngine from './ModalAddRemoteEngine' import RemoteEngineItems from './RemoteEngineItem' -import { installedEnginesAtom } from '@/helpers/atoms/Engines.atom' - const Engines = () => { - const engines = useAtomValue(installedEnginesAtom) + const { engines } = useGetEngines() return ( diff --git a/web/screens/Settings/MyModels/MyModelList/index.tsx b/web/screens/Settings/MyModels/MyModelList/index.tsx index 61f22238e0..ba21d79bd9 100644 --- a/web/screens/Settings/MyModels/MyModelList/index.tsx +++ b/web/screens/Settings/MyModels/MyModelList/index.tsx @@ -14,11 +14,12 @@ import { twMerge } from 'tailwind-merge' import { useActiveModel } from '@/hooks/useActiveModel' import useDeleteModel from '@/hooks/useDeleteModel' +import { useGetEngines } from '@/hooks/useEngineManagement' + import { toGibibytes } from '@/utils/converter' import { isLocalEngine } from '@/utils/modelEngine' -import { installedEnginesAtom } from '@/helpers/atoms/Engines.atom' import { serverEnabledAtom } from '@/helpers/atoms/LocalServer.atom' type Props = { @@ -32,7 +33,7 @@ const MyModelList = ({ model }: Props) => { const { deleteModel } = useDeleteModel() const [more, setMore] = useState(false) const [serverEnabled, setServerEnabled] = useAtom(serverEnabledAtom) - const engines = useAtomValue(installedEnginesAtom) + const { engines } = useGetEngines() const [menu, setMenu] = useState(null) const [toggle, setToggle] = useState(null) diff --git a/web/screens/Settings/SettingDetail/index.tsx b/web/screens/Settings/SettingDetail/index.tsx index 1e4b79282d..d4a2c4d82b 100644 --- a/web/screens/Settings/SettingDetail/index.tsx +++ b/web/screens/Settings/SettingDetail/index.tsx @@ -1,6 +1,8 @@ import { InferenceEngine } from '@janhq/core' import { useAtomValue } from 'jotai' +import { useGetEngines } from '@/hooks/useEngineManagement' + import Advanced from '@/screens/Settings/Advanced' import AppearanceOptions from '@/screens/Settings/Appearance' import ExtensionCatalog from '@/screens/Settings/CoreExtensions' @@ -14,12 +16,11 @@ import Privacy from '@/screens/Settings/Privacy' import { isLocalEngine } from '@/utils/modelEngine' -import { installedEnginesAtom } from '@/helpers/atoms/Engines.atom' import { selectedSettingAtom } from '@/helpers/atoms/Setting.atom' const SettingDetail = () => { const selectedSetting = useAtomValue(selectedSettingAtom) - const engines = useAtomValue(installedEnginesAtom) + const { engines } = useGetEngines() switch (selectedSetting) { case 'Engines': diff --git a/web/screens/Settings/SettingLeftPanel/index.tsx b/web/screens/Settings/SettingLeftPanel/index.tsx index 564ffc6d2a..db4c9108c9 100644 --- a/web/screens/Settings/SettingLeftPanel/index.tsx +++ b/web/screens/Settings/SettingLeftPanel/index.tsx @@ -6,12 +6,13 @@ import { useAtomValue } from 'jotai' import LeftPanelContainer from '@/containers/LeftPanelContainer' +import { useGetEngines } from '@/hooks/useEngineManagement' + import { getTitleByEngine, isLocalEngine } from '@/utils/modelEngine' import SettingItem from './SettingItem' import { extensionManager } from '@/extension' -import { installedEnginesAtom } from '@/helpers/atoms/Engines.atom' import { showSettingActiveLocalEngineAtom, @@ -20,7 +21,7 @@ import { import { janSettingScreenAtom } from '@/helpers/atoms/Setting.atom' const SettingLeftPanel = () => { - const engines = useAtomValue(installedEnginesAtom) + const { engines } = useGetEngines() const settingScreens = useAtomValue(janSettingScreenAtom) const showSettingActiveLocalEngine = useAtomValue( diff --git a/web/screens/Thread/ThreadCenterPanel/ChatBody/EmptyThread/index.tsx b/web/screens/Thread/ThreadCenterPanel/ChatBody/EmptyThread/index.tsx index ae377eb248..e69d22b489 100644 --- a/web/screens/Thread/ThreadCenterPanel/ChatBody/EmptyThread/index.tsx +++ b/web/screens/Thread/ThreadCenterPanel/ChatBody/EmptyThread/index.tsx @@ -7,16 +7,17 @@ import LogoMark from '@/containers/Brand/Logo/Mark' import { MainViewState } from '@/constants/screens' +import { useGetEngines } from '@/hooks/useEngineManagement' + import { isLocalEngine } from '@/utils/modelEngine' import { mainViewStateAtom } from '@/helpers/atoms/App.atom' -import { installedEnginesAtom } from '@/helpers/atoms/Engines.atom' import { downloadedModelsAtom } from '@/helpers/atoms/Model.atom' const EmptyThread = () => { const downloadedModels = useAtomValue(downloadedModelsAtom) const setMainViewState = useSetAtom(mainViewStateAtom) - const engines = useAtomValue(installedEnginesAtom) + const { engines } = useGetEngines() const showOnboardingStep = useMemo( () => !downloadedModels.some( diff --git a/web/screens/Thread/ThreadCenterPanel/ChatBody/OnDeviceStarterScreen/index.tsx b/web/screens/Thread/ThreadCenterPanel/ChatBody/OnDeviceStarterScreen/index.tsx index 314f84b831..70f7ef4763 100644 --- a/web/screens/Thread/ThreadCenterPanel/ChatBody/OnDeviceStarterScreen/index.tsx +++ b/web/screens/Thread/ThreadCenterPanel/ChatBody/OnDeviceStarterScreen/index.tsx @@ -24,6 +24,8 @@ import useDownloadModel from '@/hooks/useDownloadModel' import { modelDownloadStateAtom } from '@/hooks/useDownloadState' +import { useGetEngines } from '@/hooks/useEngineManagement' + import { formatDownloadPercentage, toGibibytes } from '@/utils/converter' import { manualRecommendationModel } from '@/utils/model' import { @@ -33,7 +35,6 @@ import { } from '@/utils/modelEngine' import { mainViewStateAtom } from '@/helpers/atoms/App.atom' -import { installedEnginesAtom } from '@/helpers/atoms/Engines.atom' import { configuredModelsAtom, getDownloadingModelAtom, @@ -51,7 +52,7 @@ const OnDeviceStarterScreen = ({ isShowStarterScreen }: Props) => { const { downloadModel } = useDownloadModel() const downloadStates = useAtomValue(modelDownloadStateAtom) const setSelectedSetting = useSetAtom(selectedSettingAtom) - const engines = useAtomValue(installedEnginesAtom) + const { engines } = useGetEngines() const configuredModels = useAtomValue(configuredModelsAtom) const setMainViewState = useSetAtom(mainViewStateAtom) diff --git a/web/screens/Thread/ThreadCenterPanel/ChatInput/index.tsx b/web/screens/Thread/ThreadCenterPanel/ChatInput/index.tsx index e70047d05e..457758749e 100644 --- a/web/screens/Thread/ThreadCenterPanel/ChatInput/index.tsx +++ b/web/screens/Thread/ThreadCenterPanel/ChatInput/index.tsx @@ -22,6 +22,7 @@ import { currentPromptAtom, fileUploadAtom } from '@/containers/Providers/Jotai' import { useActiveModel } from '@/hooks/useActiveModel' +import { useGetEngines } from '@/hooks/useEngineManagement' import useSendChatMessage from '@/hooks/useSendChatMessage' import { uploader } from '@/utils/file' @@ -35,7 +36,6 @@ import RichTextEditor from './RichTextEditor' import { showRightPanelAtom } from '@/helpers/atoms/App.atom' import { experimentalFeatureEnabledAtom } from '@/helpers/atoms/AppConfig.atom' import { activeAssistantAtom } from '@/helpers/atoms/Assistant.atom' -import { installedEnginesAtom } from '@/helpers/atoms/Engines.atom' import { selectedModelAtom } from '@/helpers/atoms/Model.atom' import { spellCheckAtom } from '@/helpers/atoms/Setting.atom' import { @@ -64,7 +64,7 @@ const ChatInput = () => { const textareaRef = useRef(null) const fileInputRef = useRef(null) const imageInputRef = useRef(null) - const engines = useAtomValue(installedEnginesAtom) + const { engines } = useGetEngines() const experimentalFeature = useAtomValue(experimentalFeatureEnabledAtom) const isBlockingSend = useAtomValue(isBlockingSendAtom) const activeAssistant = useAtomValue(activeAssistantAtom) diff --git a/web/screens/Thread/ThreadRightPanel/index.tsx b/web/screens/Thread/ThreadRightPanel/index.tsx index 20f365a884..ba801fd0ba 100644 --- a/web/screens/Thread/ThreadRightPanel/index.tsx +++ b/web/screens/Thread/ThreadRightPanel/index.tsx @@ -29,6 +29,7 @@ import RightPanelContainer from '@/containers/RightPanelContainer' import { useActiveModel } from '@/hooks/useActiveModel' import { useCreateNewThread } from '@/hooks/useCreateNewThread' +import { useGetEngines } from '@/hooks/useEngineManagement' import useUpdateModelParameters from '@/hooks/useUpdateModelParameters' import { getConfigurationsData } from '@/utils/componentSettings' @@ -39,7 +40,7 @@ import Tools from './Tools' import { experimentalFeatureEnabledAtom } from '@/helpers/atoms/AppConfig.atom' import { activeAssistantAtom } from '@/helpers/atoms/Assistant.atom' -import { installedEnginesAtom } from '@/helpers/atoms/Engines.atom' + import { selectedModelAtom } from '@/helpers/atoms/Model.atom' import { activeThreadAtom, @@ -61,7 +62,7 @@ const ThreadRightPanel = () => { const [activeTabThreadRightPanel, setActiveTabThreadRightPanel] = useAtom( activeTabThreadRightPanelAtom ) - const engines = useAtomValue(installedEnginesAtom) + const { engines } = useGetEngines() const { updateThreadMetadata } = useCreateNewThread() const experimentalFeature = useAtomValue(experimentalFeatureEnabledAtom)