From eeb26902ff50d77d45e74d2b8302a1d45fe745f7 Mon Sep 17 00:00:00 2001 From: Louis Date: Tue, 28 Nov 2023 11:47:17 +0700 Subject: [PATCH] chore: rebase main --- core/src/core.ts | 52 +++++-------------- core/src/fs.ts | 13 +++-- core/src/index.ts | 22 ++------ package.json | 2 +- web/containers/CardSidebar/index.tsx | 11 ++-- web/containers/DropdownListSidebar/index.tsx | 14 ++--- web/containers/ItemCardSidebar/index.tsx | 2 +- .../Layout/TopBar/CommandSearch/index.tsx | 3 +- web/hooks/useActiveModel.ts | 3 ++ web/hooks/useCreateNewThread.ts | 2 + web/hooks/useDeleteModel.ts | 3 ++ web/hooks/useGetAllThreads.ts | 3 +- web/hooks/useGetAssistants.ts | 7 ++- web/hooks/useGetDownloadedModels.ts | 2 + web/hooks/useSendChatMessage.ts | 10 +++- web/hooks/useSetActiveThread.ts | 9 ++-- web/screens/Chat/ChatBody/index.tsx | 3 -- web/screens/Chat/ChatInstruction/index.tsx | 20 +++++-- web/screens/Chat/MessageToolbar/index.tsx | 18 +++---- web/screens/Chat/Sidebar/index.tsx | 23 ++++---- web/screens/Chat/ThreadList/index.tsx | 14 +++-- web/screens/Chat/index.tsx | 3 +- 22 files changed, 117 insertions(+), 122 deletions(-) diff --git a/core/src/core.ts b/core/src/core.ts index a44a11e956..c26f867dd4 100644 --- a/core/src/core.ts +++ b/core/src/core.ts @@ -15,18 +15,6 @@ const executeOnMain: ( window.coreAPI?.invokePluginFunc(plugin, method, ...args) ?? window.electronAPI?.invokePluginFunc(plugin, method, ...args); -/** - * @deprecated This object is deprecated and should not be used. - * Use individual functions instead. - */ -const invokePluginFunc: ( - plugin: string, - method: string, - ...args: any[] -) => Promise = (plugin, method, ...args) => - window.coreAPI?.invokePluginFunc(plugin, method, ...args) ?? - window.electronAPI?.invokePluginFunc(plugin, method, ...args); - /** * Downloads a file from a URL and saves it to the local file system. * @param {string} url - The URL of the file to download. @@ -36,16 +24,7 @@ const invokePluginFunc: ( const downloadFile: (url: string, fileName: string) => Promise = ( url, fileName -) => - window.coreAPI?.downloadFile(url, fileName) ?? - window.electronAPI?.downloadFile(url, fileName); - -/** - * @deprecated This object is deprecated and should not be used. - * Use fs module instead. - */ -const deleteFile: (path: string) => Promise = (path) => - window.coreAPI?.deleteFile(path) ?? window.electronAPI?.deleteFile(path); +) => window.coreAPI?.downloadFile(url, fileName); /** * Aborts the download of a specific file. @@ -69,8 +48,16 @@ const appDataPath: () => Promise = () => window.coreAPI?.appDataPath(); const getUserSpace = (): Promise => window.coreAPI?.getUserSpace() ?? window.electronAPI?.getUserSpace(); -/** Register extension point function type definition - * +/** + * Opens the file explorer at a specific path. + * @param {string} path - The path to open in the file explorer. + * @returns {Promise} A promise that resolves when the file explorer is opened. + */ +const openFileExplorer: (path: string) => Promise = (path) => + window.coreAPI?.openFileExplorer(path); + +/** + * Register extension point function type definition */ export type RegisterExtensionPoint = ( extensionName: string, @@ -79,29 +66,14 @@ export type RegisterExtensionPoint = ( priority?: number ) => void; -/** - * @deprecated This object is deprecated and should not be used. - * Use individual functions instead. - */ -export const core = { - invokePluginFunc, - executeOnMain, - downloadFile, - abortDownload, - deleteFile, - appDataPath, - getUserSpace, -}; - /** * Functions exports */ export { - invokePluginFunc, executeOnMain, downloadFile, abortDownload, - deleteFile, appDataPath, getUserSpace, + openFileExplorer, }; diff --git a/core/src/fs.ts b/core/src/fs.ts index 460e6bf22e..b9671ce016 100644 --- a/core/src/fs.ts +++ b/core/src/fs.ts @@ -64,13 +64,13 @@ const appendFile: (path: string, data: string) => Promise = (path, data) => window.coreAPI?.appendFile(path, data) ?? window.electronAPI?.appendFile(path, data); +/** + * Reads a file line by line. + * @param {string} path - The path of the file to read. + * @returns {Promise} A promise that resolves to the lines of the file. + */ const readLineByLine: (path: string) => Promise = (path) => - window.coreAPI?.readLineByLine(path) ?? - window.electronAPI?.readLineByLine(path); - -const openFileExplorer: (path: string) => Promise = (path) => - window.coreAPI?.openFileExplorer(path) ?? - window.electronAPI?.openFileExplorer(path); + window.coreAPI?.readLineByLine(path); export const fs = { isDirectory, @@ -82,5 +82,4 @@ export const fs = { deleteFile, appendFile, readLineByLine, - openFileExplorer, }; diff --git a/core/src/index.ts b/core/src/index.ts index f7afccdb00..8d398f8b5f 100644 --- a/core/src/index.ts +++ b/core/src/index.ts @@ -1,40 +1,26 @@ -/** - * @deprecated This object is deprecated and should not be used. - * Use individual functions instead. - */ -export { core, deleteFile, invokePluginFunc } from "./core"; - /** * Core module exports. * @module */ -export { - downloadFile, - executeOnMain, - appDataPath, - getUserSpace, - abortDownload, -} from "./core"; +export * from "./core"; /** - * Events module exports. + * Events events exports. * @module */ -export { events } from "./events"; +export * from "./events"; /** * Events types exports. * @module */ -export * from "./events"; - export * from "./types/index"; /** * Filesystem module exports. * @module */ -export { fs } from "./fs"; +export * from "./fs"; /** * Plugin base module export. diff --git a/package.json b/package.json index 036542c38b..cb670a096d 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "build:web": "yarn workspace jan-web build && cpx \"web/out/**\" \"electron/renderer/\"", "build:electron": "yarn workspace jan build", "build:electron:test": "yarn workspace jan build:test", - "build:plugins": "rimraf ./electron/core/pre-install/*.tgz && concurrently --kill-others-on-fail \"cd ./plugins/conversational-json && npm install && npm run build:publish\" \"cd ./plugins/inference-plugin && npm install && npm run build:publish\" \"cd ./plugins/model-plugin && npm install && npm run build:publish\" \"cd ./plugins/monitoring-plugin && npm install && npm run build:publish\"", + "build:plugins": "rimraf ./electron/core/pre-install/*.tgz && concurrently --kill-others-on-fail \"cd ./plugins/conversational-json && npm install && npm run build:publish\" \"cd ./plugins/inference-plugin && npm install && npm run build:publish\" \"cd ./plugins/model-plugin && npm install && npm run build:publish\" \"cd ./plugins/monitoring-plugin && npm install && npm run build:publish\" \"cd ./plugins/assistant-plugin && npm install && npm run build:publish\"", "build:test": "yarn build:web && yarn workspace jan build:test", "build": "yarn build:web && yarn workspace jan build", "build:publish": "yarn build:web && yarn workspace jan build:publish" diff --git a/web/containers/CardSidebar/index.tsx b/web/containers/CardSidebar/index.tsx index 61f3c20e51..42f975aafd 100644 --- a/web/containers/CardSidebar/index.tsx +++ b/web/containers/CardSidebar/index.tsx @@ -1,10 +1,12 @@ import { ReactNode, useState } from 'react' import { Fragment } from 'react' + import { Menu, Transition } from '@headlessui/react' import { ChevronDownIcon, EllipsisVerticalIcon, } from '@heroicons/react/20/solid' +import { twMerge } from 'tailwind-merge' interface Props { children: ReactNode @@ -12,11 +14,6 @@ interface Props { onRevealInFinderClick: (type: string) => void onViewJsonClick: (type: string) => void } - -function classNames(...classes: any) { - return classes.filter(Boolean).join(' ') -} - export default function CardSidebar({ children, title, @@ -58,7 +55,7 @@ export default function CardSidebar({ {({ active }) => ( onRevealInFinderClick(title)} - className={classNames( + className={twMerge( active ? 'bg-gray-50' : '', 'block cursor-pointer px-3 py-1 text-xs leading-6 text-gray-900' )} @@ -71,7 +68,7 @@ export default function CardSidebar({ {({ active }) => ( onViewJsonClick(title)} - className={classNames( + className={twMerge( active ? 'bg-gray-50' : '', 'block cursor-pointer px-3 py-1 text-xs leading-6 text-gray-900' )} diff --git a/web/containers/DropdownListSidebar/index.tsx b/web/containers/DropdownListSidebar/index.tsx index 1cab4ce0df..91d194fbdb 100644 --- a/web/containers/DropdownListSidebar/index.tsx +++ b/web/containers/DropdownListSidebar/index.tsx @@ -1,13 +1,13 @@ import { Fragment, useEffect, useState } from 'react' + import { Listbox, Transition } from '@headlessui/react' import { CheckIcon, ChevronUpDownIcon } from '@heroicons/react/20/solid' -import { getDownloadedModels } from '@/hooks/useGetDownloadedModels' + import { Model } from '@janhq/core/lib/types' import { atom, useSetAtom } from 'jotai' +import { twMerge } from 'tailwind-merge' -function classNames(...classes: any) { - return classes.filter(Boolean).join(' ') -} +import { getDownloadedModels } from '@/hooks/useGetDownloadedModels' export const selectedModelAtom = atom(undefined) @@ -62,7 +62,7 @@ export default function DropdownListSidebar() { - classNames( + twMerge( active ? 'bg-indigo-600 text-white' : 'text-gray-900', 'relative cursor-default select-none py-2 pl-3 pr-9' ) @@ -72,7 +72,7 @@ export default function DropdownListSidebar() { {({ selected, active }) => ( <>
{title} -
+ (undefined) diff --git a/web/hooks/useCreateNewThread.ts b/web/hooks/useCreateNewThread.ts index c397b329c5..7cd34973c4 100644 --- a/web/hooks/useCreateNewThread.ts +++ b/web/hooks/useCreateNewThread.ts @@ -5,7 +5,9 @@ import { ThreadState, } from '@janhq/core/lib/types' import { atom, useAtom, useAtomValue, useSetAtom } from 'jotai' + import { generateThreadId } from '@/utils/conversation' + import { threadsAtom, setActiveThreadIdAtom, diff --git a/web/hooks/useDeleteModel.ts b/web/hooks/useDeleteModel.ts index 6dada49be4..696943f4ac 100644 --- a/web/hooks/useDeleteModel.ts +++ b/web/hooks/useDeleteModel.ts @@ -1,8 +1,11 @@ import { PluginType } from '@janhq/core' import { ModelPlugin } from '@janhq/core/lib/plugins' import { Model } from '@janhq/core/lib/types' + import { toaster } from '@/containers/Toast' + import { useGetDownloadedModels } from '@/hooks/useGetDownloadedModels' + import { pluginManager } from '@/plugin/PluginManager' export default function useDeleteModel() { diff --git a/web/hooks/useGetAllThreads.ts b/web/hooks/useGetAllThreads.ts index 8f9a1a39f3..e27b9a0391 100644 --- a/web/hooks/useGetAllThreads.ts +++ b/web/hooks/useGetAllThreads.ts @@ -1,6 +1,7 @@ import { PluginType, ThreadState } from '@janhq/core' import { ConversationalPlugin } from '@janhq/core/lib/plugins' import { useSetAtom } from 'jotai' + import { threadStatesAtom, threadsAtom, @@ -19,7 +20,7 @@ const useGetAllThreads = () => { const threadStates: Record = {} threads?.forEach((thread) => { if (thread.id != null) { - const lastMessage = thread.metadata?.lastMessage ?? '' + const lastMessage = (thread.metadata?.lastMessage as string) ?? '' threadStates[thread.id] = { hasMore: true, waitingForResponse: false, diff --git a/web/hooks/useGetAssistants.ts b/web/hooks/useGetAssistants.ts index c899a46b85..0d16add285 100644 --- a/web/hooks/useGetAssistants.ts +++ b/web/hooks/useGetAssistants.ts @@ -1,7 +1,10 @@ -import { pluginManager } from '@/plugin/PluginManager' +import { useEffect, useState } from 'react' + import { Assistant, PluginType } from '@janhq/core' + import { AssistantPlugin } from '@janhq/core/lib/plugins' -import { useEffect, useState } from 'react' + +import { pluginManager } from '@/plugin/PluginManager' const getAssistants = async (): Promise => { return ( diff --git a/web/hooks/useGetDownloadedModels.ts b/web/hooks/useGetDownloadedModels.ts index c51b62ea88..766ff1b9a2 100644 --- a/web/hooks/useGetDownloadedModels.ts +++ b/web/hooks/useGetDownloadedModels.ts @@ -1,7 +1,9 @@ import { useEffect, useState } from 'react' + import { PluginType } from '@janhq/core' import { ModelPlugin } from '@janhq/core/lib/plugins' import { Model } from '@janhq/core/lib/types' + import { pluginManager } from '@/plugin/PluginManager' export function useGetDownloadedModels() { diff --git a/web/hooks/useSendChatMessage.ts b/web/hooks/useSendChatMessage.ts index 071141eb86..02723bfd09 100644 --- a/web/hooks/useSendChatMessage.ts +++ b/web/hooks/useSendChatMessage.ts @@ -15,6 +15,7 @@ import { useAtom, useAtomValue, useSetAtom } from 'jotai' import { ulid } from 'ulid' +import { selectedModelAtom } from '@/containers/DropdownListSidebar' import { currentPromptAtom } from '@/containers/Providers/Jotai' import { useActiveModel } from './useActiveModel' @@ -29,7 +30,6 @@ import { updateConversationWaitingForResponseAtom, } from '@/helpers/atoms/Conversation.atom' import { pluginManager } from '@/plugin/PluginManager' -import { selectedModelAtom } from '@/containers/DropdownListSidebar' export default function useSendChatMessage() { const activeThread = useAtomValue(activeThreadAtom) @@ -41,6 +41,7 @@ export default function useSendChatMessage() { const currentMessages = useAtomValue(getCurrentChatMessagesAtom) const { activeModel } = useActiveModel() const selectedModel = useAtomValue(selectedModelAtom) + const { startModel } = useActiveModel() function updateThreadTitle(newMessage: MessageRequest) { if ( @@ -169,12 +170,17 @@ export default function useSendChatMessage() { } addNewMessage(threadMessage) + updateThreadTitle(messageRequest) + await pluginManager .get(PluginType.Conversational) ?.addNewMessage(threadMessage) + const modelId = selectedModel?.id ?? activeThread.assistants[0].model.id + if (activeModel?.id !== modelId) { + await startModel(modelId) + } events.emit(EventName.OnNewMessageRequest, messageRequest) - updateThreadTitle(messageRequest) } return { diff --git a/web/hooks/useSetActiveThread.ts b/web/hooks/useSetActiveThread.ts index 1137b6cbb9..36e69a14a1 100644 --- a/web/hooks/useSetActiveThread.ts +++ b/web/hooks/useSetActiveThread.ts @@ -1,12 +1,15 @@ +import { PluginType, Thread } from '@janhq/core' + +import { ConversationalPlugin } from '@janhq/core/lib/plugins' + +import { useAtomValue, useSetAtom } from 'jotai' + import { setConvoMessagesAtom } from '@/helpers/atoms/ChatMessage.atom' import { getActiveThreadIdAtom, setActiveThreadIdAtom, } from '@/helpers/atoms/Conversation.atom' import { pluginManager } from '@/plugin' -import { PluginType, Thread } from '@janhq/core' -import { ConversationalPlugin } from '@janhq/core/lib/plugins' -import { useAtomValue, useSetAtom } from 'jotai' export default function useSetActiveThread() { const activeThreadId = useAtomValue(getActiveThreadIdAtom) diff --git a/web/screens/Chat/ChatBody/index.tsx b/web/screens/Chat/ChatBody/index.tsx index a477f75dc6..8fc59ab121 100644 --- a/web/screens/Chat/ChatBody/index.tsx +++ b/web/screens/Chat/ChatBody/index.tsx @@ -4,9 +4,6 @@ import ChatInstruction from '../ChatInstruction' import ChatItem from '../ChatItem' import { getCurrentChatMessagesAtom } from '@/helpers/atoms/ChatMessage.atom' -import { useActiveModel } from '@/hooks/useActiveModel' -import { activeThreadAtom } from '@/helpers/atoms/Conversation.atom' -import { useEffect } from 'react' const ChatBody: React.FC = () => { const messages = useAtomValue(getCurrentChatMessagesAtom) diff --git a/web/screens/Chat/ChatInstruction/index.tsx b/web/screens/Chat/ChatInstruction/index.tsx index bff82101e9..1f927f6ce5 100644 --- a/web/screens/Chat/ChatInstruction/index.tsx +++ b/web/screens/Chat/ChatInstruction/index.tsx @@ -2,6 +2,7 @@ import { useState } from 'react' import { ChatCompletionRole, + ContentType, EventName, MessageStatus, ThreadMessage, @@ -11,20 +12,29 @@ import { import { Button, Textarea } from '@janhq/uikit' import { useAtomValue } from 'jotai' -import { getActiveConvoIdAtom } from '@/helpers/atoms/Conversation.atom' +import { getActiveThreadIdAtom } from '@/helpers/atoms/Conversation.atom' const ChatInstruction = () => { - const activeConvoId = useAtomValue(getActiveConvoIdAtom) + const activeConvoId = useAtomValue(getActiveThreadIdAtom) const [isSettingInstruction, setIsSettingInstruction] = useState(false) const [instruction, setInstruction] = useState('') const setSystemPrompt = (instruction: string) => { + if (!activeConvoId) return + const message: ThreadMessage = { id: 'system-prompt', - content: instruction, + content: [ + { + type: ContentType.Text, + text: { value: instruction, annotations: [] }, + }, + ], role: ChatCompletionRole.System, status: MessageStatus.Ready, - createdAt: new Date().toISOString(), - threadId: activeConvoId, + thread_id: activeConvoId, + created: Date.now(), + updated: Date.now(), + object: 'message', } events.emit(EventName.OnNewMessageResponse, message) events.emit(EventName.OnMessageResponseFinished, message) diff --git a/web/screens/Chat/MessageToolbar/index.tsx b/web/screens/Chat/MessageToolbar/index.tsx index 5b2a9ccf8d..006bc9e164 100644 --- a/web/screens/Chat/MessageToolbar/index.tsx +++ b/web/screens/Chat/MessageToolbar/index.tsx @@ -18,12 +18,12 @@ import { deleteMessage, getCurrentChatMessagesAtom, } from '@/helpers/atoms/ChatMessage.atom' -import { currentConversationAtom } from '@/helpers/atoms/Conversation.atom' +import { activeThreadAtom } from '@/helpers/atoms/Conversation.atom' import { pluginManager } from '@/plugin' const MessageToolbar = ({ message }: { message: ThreadMessage }) => { const deleteAMessage = useSetAtom(deleteMessage) - const thread = useAtomValue(currentConversationAtom) + const thread = useAtomValue(activeThreadAtom) const messages = useAtomValue(getCurrentChatMessagesAtom) const stopInference = async () => { await pluginManager @@ -55,12 +55,13 @@ const MessageToolbar = ({ message }: { message: ThreadMessage }) => { .slice(1, messages.length) .reverse() .map((e) => { - return { - content: e.content, + const msg: ChatCompletionMessage = { role: e.role, - } as ChatCompletionMessage + content: e.content[0].text.value, + } + return msg }), - threadId: message.threadId ?? '', + threadId: message.thread_id ?? '', } if (message.role === ChatCompletionRole.Assistant) { deleteAMessage(message.id ?? '') @@ -74,7 +75,7 @@ const MessageToolbar = ({ message }: { message: ThreadMessage }) => {
{ - navigator.clipboard.writeText(message.content ?? '') + navigator.clipboard.writeText(message.content[0]?.text?.value ?? '') toaster({ title: 'Copied to clipboard', }) @@ -89,9 +90,8 @@ const MessageToolbar = ({ message }: { message: ThreadMessage }) => { if (thread) await pluginManager .get(PluginType.Conversational) - ?.saveConversation({ + ?.saveThread({ ...thread, - messages: messages.filter((e) => e.id !== message.id), }) }} > diff --git a/web/screens/Chat/Sidebar/index.tsx b/web/screens/Chat/Sidebar/index.tsx index 2274f1df91..5396f5ec44 100644 --- a/web/screens/Chat/Sidebar/index.tsx +++ b/web/screens/Chat/Sidebar/index.tsx @@ -1,12 +1,15 @@ +import { join } from 'path' + +import { getUserSpace, openFileExplorer } from '@janhq/core' +import { atom, useAtomValue } from 'jotai' + import CardSidebar from '@/containers/CardSidebar' -import ItemCardSidebar from '@/containers/ItemCardSidebar' import DropdownListSidebar, { selectedModelAtom, } from '@/containers/DropdownListSidebar' -import { atom, useAtom, useAtomValue } from 'jotai' +import ItemCardSidebar from '@/containers/ItemCardSidebar' + import { activeThreadAtom } from '@/helpers/atoms/Conversation.atom' -import { fs } from '@janhq/core' -import { join } from 'path' export const showRightSideBarAtom = atom(false) @@ -22,8 +25,9 @@ export default function Sidebar() { return } - const userSpace = await fs.getUserSpace() + const userSpace = await getUserSpace() let filePath = undefined + const assistantId = activeThread.assistants[0]?.assistant_id switch (type) { case 'Thread': filePath = join('threads', activeThread.id) @@ -33,7 +37,6 @@ export default function Sidebar() { filePath = join('models', selectedModel.id) break case 'Assistant': - const assistantId = activeThread.assistants[0]?.id if (!assistantId) return filePath = join('assistants', assistantId) break @@ -45,7 +48,7 @@ export default function Sidebar() { const fullPath = join(userSpace, filePath) console.log(fullPath) - fs.openFileExplorer(fullPath) + openFileExplorer(fullPath) } const onViewJsonClick = async (type: string) => { @@ -55,8 +58,9 @@ export default function Sidebar() { return } - const userSpace = await fs.getUserSpace() + const userSpace = await getUserSpace() let filePath = undefined + const assistantId = activeThread.assistants[0]?.assistant_id switch (type) { case 'Thread': filePath = join('threads', activeThread.id, 'thread.json') @@ -66,7 +70,6 @@ export default function Sidebar() { filePath = join('models', selectedModel.id, 'model.json') break case 'Assistant': - const assistantId = activeThread.assistants[0]?.id if (!assistantId) return filePath = join('assistants', assistantId, 'assistant.json') break @@ -78,7 +81,7 @@ export default function Sidebar() { const fullPath = join(userSpace, filePath) console.log(fullPath) - fs.openFileExplorer(fullPath) + openFileExplorer(fullPath) } return ( diff --git a/web/screens/Chat/ThreadList/index.tsx b/web/screens/Chat/ThreadList/index.tsx index d5af77875c..6e468b49fa 100644 --- a/web/screens/Chat/ThreadList/index.tsx +++ b/web/screens/Chat/ThreadList/index.tsx @@ -1,18 +1,24 @@ +import { useEffect } from 'react' + import { Button } from '@janhq/uikit' import { motion as m } from 'framer-motion' import { useAtomValue } from 'jotai' import { GalleryHorizontalEndIcon } from 'lucide-react' import { twMerge } from 'tailwind-merge' + import { useCreateNewThread } from '@/hooks/useCreateNewThread' + +import useGetAllThreads from '@/hooks/useGetAllThreads' +import useGetAssistants from '@/hooks/useGetAssistants' + +import useSetActiveThread from '@/hooks/useSetActiveThread' + import { displayDate } from '@/utils/datetime' + import { threadStatesAtom, threadsAtom, } from '@/helpers/atoms/Conversation.atom' -import useGetAssistants from '@/hooks/useGetAssistants' -import useSetActiveThread from '@/hooks/useSetActiveThread' -import useGetAllThreads from '@/hooks/useGetAllThreads' -import { useEffect } from 'react' export default function ThreadList() { const threads = useAtomValue(threadsAtom) diff --git a/web/screens/Chat/index.tsx b/web/screens/Chat/index.tsx index 9767d336db..d5fdfa1166 100644 --- a/web/screens/Chat/index.tsx +++ b/web/screens/Chat/index.tsx @@ -29,6 +29,8 @@ import ChatBody from '@/screens/Chat/ChatBody' import ThreadList from '@/screens/Chat/ThreadList' +import Sidebar from './Sidebar' + import { activeThreadAtom, getActiveThreadIdAtom, @@ -37,7 +39,6 @@ import { } from '@/helpers/atoms/Conversation.atom' import { activeThreadStateAtom } from '@/helpers/atoms/Conversation.atom' -import Sidebar from './Sidebar' const ChatScreen = () => { const currentConvo = useAtomValue(activeThreadAtom)