* add platform guards * add service management * fix types * move to zustand for servicehub * update App Updater * update tauri missing move * update app updater * refactor: move PlatformFeatures to separate const file 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * change tauri fetch name * update implementation * update extension fetch * make web version run properly * disabled unused web settings * fix all tests * fix lint * fix tests * add mock for extension * fix build * update make and mise * fix tsconfig for web-extensions * fix loader type * cleanup * fix test * update error handling + mcp should be working * Update mcp init * use separate is_web_app build property * Remove fixed model catalog url * fix additional tests * fix download issue (event emitter not implemented correctly) * Update Title html * fix app logs * update root tsx render timing --------- Co-authored-by: Claude <noreply@anthropic.com>
125 lines
5.0 KiB
TypeScript
125 lines
5.0 KiB
TypeScript
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<AssistantState>()((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)
|
||
}
|
||
}
|
||
},
|
||
}))
|