fix: cleaning a thread should just clear out messages (#4316)
* fix: cleaning a thread should just clear out messages * chore: clean up
This commit is contained in:
parent
abb718c57f
commit
24222679fb
@ -147,7 +147,9 @@ export default class CortexConversationalExtension extends ConversationalExtensi
|
|||||||
*/
|
*/
|
||||||
async getThreadAssistant(threadId: string): Promise<ThreadAssistantInfo> {
|
async getThreadAssistant(threadId: string): Promise<ThreadAssistantInfo> {
|
||||||
return this.queue.add(() =>
|
return this.queue.add(() =>
|
||||||
ky.get(`${API_URL}/v1/assistants/${threadId}?limit=-1`).json<ThreadAssistantInfo>()
|
ky
|
||||||
|
.get(`${API_URL}/v1/assistants/${threadId}?limit=-1`)
|
||||||
|
.json<ThreadAssistantInfo>()
|
||||||
) as Promise<ThreadAssistantInfo>
|
) as Promise<ThreadAssistantInfo>
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -188,7 +190,7 @@ export default class CortexConversationalExtension extends ConversationalExtensi
|
|||||||
* Do health check on cortex.cpp
|
* Do health check on cortex.cpp
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
healthz(): Promise<void> {
|
async healthz(): Promise<void> {
|
||||||
return ky
|
return ky
|
||||||
.get(`${API_URL}/healthz`, {
|
.get(`${API_URL}/healthz`, {
|
||||||
retry: { limit: 20, delay: () => 500, methods: ['get'] },
|
retry: { limit: 20, delay: () => 500, methods: ['get'] },
|
||||||
|
|||||||
@ -125,6 +125,26 @@ export const waitingToSendMessage = atom<boolean | undefined>(undefined)
|
|||||||
*/
|
*/
|
||||||
export const isGeneratingResponseAtom = atom<boolean | undefined>(undefined)
|
export const isGeneratingResponseAtom = atom<boolean | undefined>(undefined)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new thread and add it to the thread list
|
||||||
|
*/
|
||||||
|
export const createNewThreadAtom = atom(null, (get, set, newThread: Thread) => {
|
||||||
|
// create thread state for this new thread
|
||||||
|
const currentState = { ...get(threadStatesAtom) }
|
||||||
|
|
||||||
|
const threadState: ThreadState = {
|
||||||
|
hasMore: false,
|
||||||
|
waitingForResponse: false,
|
||||||
|
lastMessage: undefined,
|
||||||
|
}
|
||||||
|
currentState[newThread.id] = threadState
|
||||||
|
set(threadStatesAtom, currentState)
|
||||||
|
|
||||||
|
// add the new thread on top of the thread list to the state
|
||||||
|
const threads = get(threadsAtom)
|
||||||
|
set(threadsAtom, [newThread, ...threads])
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a thread state from the atom
|
* Remove a thread state from the atom
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -33,29 +33,12 @@ import { activeAssistantAtom } from '@/helpers/atoms/Assistant.atom'
|
|||||||
import { selectedModelAtom } from '@/helpers/atoms/Model.atom'
|
import { selectedModelAtom } from '@/helpers/atoms/Model.atom'
|
||||||
import {
|
import {
|
||||||
threadsAtom,
|
threadsAtom,
|
||||||
threadStatesAtom,
|
|
||||||
updateThreadAtom,
|
updateThreadAtom,
|
||||||
setThreadModelParamsAtom,
|
setThreadModelParamsAtom,
|
||||||
isGeneratingResponseAtom,
|
isGeneratingResponseAtom,
|
||||||
|
createNewThreadAtom,
|
||||||
} from '@/helpers/atoms/Thread.atom'
|
} from '@/helpers/atoms/Thread.atom'
|
||||||
|
|
||||||
const createNewThreadAtom = atom(null, (get, set, newThread: Thread) => {
|
|
||||||
// create thread state for this new thread
|
|
||||||
const currentState = { ...get(threadStatesAtom) }
|
|
||||||
|
|
||||||
const threadState: ThreadState = {
|
|
||||||
hasMore: false,
|
|
||||||
waitingForResponse: false,
|
|
||||||
lastMessage: undefined,
|
|
||||||
}
|
|
||||||
currentState[newThread.id] = threadState
|
|
||||||
set(threadStatesAtom, currentState)
|
|
||||||
|
|
||||||
// add the new thread on top of the thread list to the state
|
|
||||||
const threads = get(threadsAtom)
|
|
||||||
set(threadsAtom, [newThread, ...threads])
|
|
||||||
})
|
|
||||||
|
|
||||||
export const useCreateNewThread = () => {
|
export const useCreateNewThread = () => {
|
||||||
const createNewThread = useSetAtom(createNewThreadAtom)
|
const createNewThread = useSetAtom(createNewThreadAtom)
|
||||||
const { setActiveThread } = useSetActiveThread()
|
const { setActiveThread } = useSetActiveThread()
|
||||||
|
|||||||
@ -55,17 +55,21 @@ describe('useDeleteThread', () => {
|
|||||||
const mockCleanMessages = jest.fn()
|
const mockCleanMessages = jest.fn()
|
||||||
;(useSetAtom as jest.Mock).mockReturnValue(() => mockCleanMessages)
|
;(useSetAtom as jest.Mock).mockReturnValue(() => mockCleanMessages)
|
||||||
;(useAtomValue as jest.Mock).mockReturnValue(['thread 1'])
|
;(useAtomValue as jest.Mock).mockReturnValue(['thread 1'])
|
||||||
const mockCreateNewThread = jest.fn()
|
|
||||||
;(useCreateNewThread as jest.Mock).mockReturnValue({
|
|
||||||
requestCreateNewThread: mockCreateNewThread,
|
|
||||||
})
|
|
||||||
|
|
||||||
const mockSaveThread = jest.fn()
|
const mockSaveThread = jest.fn()
|
||||||
const mockDeleteThread = jest.fn().mockResolvedValue({})
|
const mockDeleteMessage = jest.fn().mockResolvedValue({})
|
||||||
|
const mockModifyThread = jest.fn().mockResolvedValue({})
|
||||||
extensionManager.get = jest.fn().mockReturnValue({
|
extensionManager.get = jest.fn().mockReturnValue({
|
||||||
saveThread: mockSaveThread,
|
saveThread: mockSaveThread,
|
||||||
getThreadAssistant: jest.fn().mockResolvedValue({}),
|
getThreadAssistant: jest.fn().mockResolvedValue({}),
|
||||||
deleteThread: mockDeleteThread,
|
listMessages: jest.fn().mockResolvedValue([
|
||||||
|
{
|
||||||
|
id: 'message1',
|
||||||
|
text: 'Message 1',
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
deleteMessage: mockDeleteMessage,
|
||||||
|
modifyThread: mockModifyThread,
|
||||||
})
|
})
|
||||||
|
|
||||||
const { result } = renderHook(() => useDeleteThread())
|
const { result } = renderHook(() => useDeleteThread())
|
||||||
@ -74,8 +78,8 @@ describe('useDeleteThread', () => {
|
|||||||
await result.current.cleanThread('thread1')
|
await result.current.cleanThread('thread1')
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(mockDeleteThread).toHaveBeenCalled()
|
expect(mockDeleteMessage).toHaveBeenCalled()
|
||||||
expect(mockCreateNewThread).toHaveBeenCalled()
|
expect(mockModifyThread).toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should handle errors when deleting a thread', async () => {
|
it('should handle errors when deleting a thread', async () => {
|
||||||
|
|||||||
@ -2,30 +2,25 @@ import { useCallback } from 'react'
|
|||||||
|
|
||||||
import { ExtensionTypeEnum, ConversationalExtension } from '@janhq/core'
|
import { ExtensionTypeEnum, ConversationalExtension } from '@janhq/core'
|
||||||
|
|
||||||
import { useAtom, useAtomValue, useSetAtom } from 'jotai'
|
import { useAtom, useSetAtom } from 'jotai'
|
||||||
|
|
||||||
import { currentPromptAtom } from '@/containers/Providers/Jotai'
|
import { currentPromptAtom } from '@/containers/Providers/Jotai'
|
||||||
|
|
||||||
import { toaster } from '@/containers/Toast'
|
import { toaster } from '@/containers/Toast'
|
||||||
|
|
||||||
import { useCreateNewThread } from './useCreateNewThread'
|
|
||||||
|
|
||||||
import { extensionManager } from '@/extension/ExtensionManager'
|
import { extensionManager } from '@/extension/ExtensionManager'
|
||||||
|
|
||||||
import { assistantsAtom } from '@/helpers/atoms/Assistant.atom'
|
|
||||||
import { deleteChatMessageAtom as deleteChatMessagesAtom } from '@/helpers/atoms/ChatMessage.atom'
|
import { deleteChatMessageAtom as deleteChatMessagesAtom } from '@/helpers/atoms/ChatMessage.atom'
|
||||||
import { downloadedModelsAtom } from '@/helpers/atoms/Model.atom'
|
|
||||||
import {
|
import {
|
||||||
threadsAtom,
|
threadsAtom,
|
||||||
setActiveThreadIdAtom,
|
setActiveThreadIdAtom,
|
||||||
deleteThreadStateAtom,
|
deleteThreadStateAtom,
|
||||||
|
updateThreadAtom,
|
||||||
} from '@/helpers/atoms/Thread.atom'
|
} from '@/helpers/atoms/Thread.atom'
|
||||||
|
|
||||||
export default function useDeleteThread() {
|
export default function useDeleteThread() {
|
||||||
const [threads, setThreads] = useAtom(threadsAtom)
|
const [threads, setThreads] = useAtom(threadsAtom)
|
||||||
const { requestCreateNewThread } = useCreateNewThread()
|
const updateThread = useSetAtom(updateThreadAtom)
|
||||||
const assistants = useAtomValue(assistantsAtom)
|
|
||||||
const models = useAtomValue(downloadedModelsAtom)
|
|
||||||
|
|
||||||
const setCurrentPrompt = useSetAtom(currentPromptAtom)
|
const setCurrentPrompt = useSetAtom(currentPromptAtom)
|
||||||
const setActiveThreadId = useSetAtom(setActiveThreadIdAtom)
|
const setActiveThreadId = useSetAtom(setActiveThreadIdAtom)
|
||||||
@ -35,43 +30,37 @@ export default function useDeleteThread() {
|
|||||||
|
|
||||||
const cleanThread = useCallback(
|
const cleanThread = useCallback(
|
||||||
async (threadId: string) => {
|
async (threadId: string) => {
|
||||||
const thread = threads.find((c) => c.id === threadId)
|
const messages = await extensionManager
|
||||||
if (!thread) return
|
|
||||||
const availableThreads = threads.filter((c) => c.id !== threadId)
|
|
||||||
setThreads(availableThreads)
|
|
||||||
|
|
||||||
// delete the thread state
|
|
||||||
deleteThreadState(threadId)
|
|
||||||
|
|
||||||
const assistantInfo = await extensionManager
|
|
||||||
.get<ConversationalExtension>(ExtensionTypeEnum.Conversational)
|
.get<ConversationalExtension>(ExtensionTypeEnum.Conversational)
|
||||||
?.getThreadAssistant(thread.id)
|
?.listMessages(threadId)
|
||||||
.catch(console.error)
|
.catch(console.error)
|
||||||
|
if (messages) {
|
||||||
if (!assistantInfo) return
|
messages.forEach((message) => {
|
||||||
const model = models.find((c) => c.id === assistantInfo?.model?.id)
|
extensionManager
|
||||||
|
.get<ConversationalExtension>(ExtensionTypeEnum.Conversational)
|
||||||
requestCreateNewThread(
|
?.deleteMessage(threadId, message.id)
|
||||||
{
|
.catch(console.error)
|
||||||
...assistantInfo,
|
})
|
||||||
id: assistants[0].id,
|
const thread = threads.find((e) => e.id === threadId)
|
||||||
name: assistants[0].name,
|
if (thread) {
|
||||||
|
const updatedThread = {
|
||||||
|
...thread,
|
||||||
|
metadata: {
|
||||||
|
...thread.metadata,
|
||||||
|
title: 'New Thread',
|
||||||
|
lastMessage: '',
|
||||||
},
|
},
|
||||||
model
|
|
||||||
? {
|
|
||||||
...model,
|
|
||||||
parameters: assistantInfo?.model?.parameters ?? {},
|
|
||||||
settings: assistantInfo?.model?.settings ?? {},
|
|
||||||
}
|
}
|
||||||
: undefined
|
extensionManager
|
||||||
)
|
|
||||||
// Delete this thread
|
|
||||||
await extensionManager
|
|
||||||
.get<ConversationalExtension>(ExtensionTypeEnum.Conversational)
|
.get<ConversationalExtension>(ExtensionTypeEnum.Conversational)
|
||||||
?.deleteThread(threadId)
|
?.modifyThread(updatedThread)
|
||||||
.catch(console.error)
|
.catch(console.error)
|
||||||
|
updateThread(updatedThread)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deleteMessages(threadId)
|
||||||
},
|
},
|
||||||
[assistants, models, requestCreateNewThread, threads]
|
[deleteMessages, threads, updateThread]
|
||||||
)
|
)
|
||||||
|
|
||||||
const deleteThread = async (threadId: string) => {
|
const deleteThread = async (threadId: string) => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user