import { getServiceHub } from '@/hooks/useServiceHub' import { Assistant as CoreAssistant } from '@janhq/core' import { create } from 'zustand' import { localStorageKey } from '@/constants/localStorage' interface AssistantState { assistants: Assistant[] currentAssistant: Assistant addAssistant: (assistant: Assistant) => void updateAssistant: (assistant: Assistant) => void deleteAssistant: (id: string) => void setCurrentAssistant: (assistant: Assistant, saveToStorage?: boolean) => void setAssistants: (assistants: Assistant[]) => void getLastUsedAssistant: () => string | null setLastUsedAssistant: (assistantId: string) => void initializeWithLastUsed: () => void } // Helper functions for localStorage const getLastUsedAssistantId = (): string | null => { try { return localStorage.getItem(localStorageKey.lastUsedAssistant) } catch (error) { console.debug('Failed to get last used assistant from localStorage:', error) return null } } const setLastUsedAssistantId = (assistantId: string) => { try { localStorage.setItem(localStorageKey.lastUsedAssistant, assistantId) } catch (error) { console.debug('Failed to set last used assistant in localStorage:', error) } } export const defaultAssistant: Assistant = { id: 'jan', name: 'Jan', created_at: 1747029866.542, parameters: {}, avatar: '👋', description: 'Jan is a helpful desktop assistant that can reason through complex tasks and use tools to complete them on the user’s behalf.', instructions: 'You are a helpful AI assistant. Your primary goal is to assist users with their questions and tasks to the best of your abilities.\n\nWhen responding:\n- Answer directly from your knowledge when you can\n- Be concise, clear, and helpful\n- Admit when you’re unsure rather than making things up\n\nIf tools are available to you:\n- Only use tools when they add real value to your response\n- Use tools when the user explicitly asks (e.g., "search for...", "calculate...", "run this code")\n- Use tools for information you don’t know or that needs verification\n- Never use tools just because they’re available\n\nWhen using tools:\n- Use one tool at a time and wait for results\n- Use actual values as arguments, not variable names\n- Learn from each result before deciding next steps\n- Avoid repeating the same tool call with identical parameters\n\nRemember: Most questions can be answered without tools. Think first whether you need them.\n\nCurrent date: {{current_date}}', } export const useAssistant = create()((set, get) => ({ assistants: [defaultAssistant], currentAssistant: defaultAssistant, addAssistant: (assistant) => { set({ assistants: [...get().assistants, assistant] }) getServiceHub().assistants().createAssistant(assistant as unknown as CoreAssistant).catch((error) => { console.error('Failed to create assistant:', error) }) }, updateAssistant: (assistant) => { const state = get() set({ assistants: state.assistants.map((a) => a.id === assistant.id ? assistant : a ), // Update currentAssistant if it's the same assistant being updated currentAssistant: state.currentAssistant.id === assistant.id ? assistant : state.currentAssistant, }) // Create assistant already cover update logic getServiceHub().assistants().createAssistant(assistant as unknown as CoreAssistant).catch((error) => { console.error('Failed to update assistant:', error) }) }, deleteAssistant: (id) => { const state = get() getServiceHub().assistants().deleteAssistant( state.assistants.find((e) => e.id === id) as unknown as CoreAssistant ).catch((error) => { console.error('Failed to delete assistant:', error) }) // Check if we're deleting the current assistant const wasCurrentAssistant = state.currentAssistant.id === id set({ assistants: state.assistants.filter((a) => a.id !== id) }) // If the deleted assistant was current, fallback to default and update localStorage if (wasCurrentAssistant) { set({ currentAssistant: defaultAssistant }) setLastUsedAssistantId(defaultAssistant.id) } }, setCurrentAssistant: (assistant, saveToStorage = true) => { set({ currentAssistant: assistant }) if (saveToStorage) { setLastUsedAssistantId(assistant.id) } }, setAssistants: (assistants) => { set({ assistants }) }, getLastUsedAssistant: () => { return getLastUsedAssistantId() }, setLastUsedAssistant: (assistantId) => { setLastUsedAssistantId(assistantId) }, initializeWithLastUsed: () => { const lastUsedId = getLastUsedAssistantId() if (lastUsedId) { const lastUsedAssistant = get().assistants.find( (a) => a.id === lastUsedId ) if (lastUsedAssistant) { set({ currentAssistant: lastUsedAssistant }) } else { // Fallback to default if last used assistant was deleted set({ currentAssistant: defaultAssistant }) setLastUsedAssistantId(defaultAssistant.id) } } }, }))