Merge branch 'v2' into feat/router-design

This commit is contained in:
MyPrototypeWhat 2025-12-10 11:35:45 +08:00 committed by GitHub
commit ec3c9db9ff
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 190 additions and 191 deletions

View File

@ -41,6 +41,7 @@ export type UseCacheSchema = {
'chat.generating': boolean 'chat.generating': boolean
'chat.websearch.searching': boolean 'chat.websearch.searching': boolean
'chat.websearch.active_searches': CacheValueTypes.CacheActiveSearches 'chat.websearch.active_searches': CacheValueTypes.CacheActiveSearches
'chat.active_view': 'topic' | 'session'
// Minapp management // Minapp management
'minapp.opened_keep_alive': CacheValueTypes.CacheMinAppType[] 'minapp.opened_keep_alive': CacheValueTypes.CacheMinAppType[]
@ -52,6 +53,11 @@ export type UseCacheSchema = {
'topic.active': CacheValueTypes.CacheTopic | null 'topic.active': CacheValueTypes.CacheTopic | null
'topic.renaming': string[] 'topic.renaming': string[]
'topic.newly_renamed': string[] 'topic.newly_renamed': string[]
// Agent management
'agent.active_id': string | null
'agent.session.active_id_map': Record<string, string | null>
'agent.session.waiting_id_map': Record<string, boolean>
} }
export const DefaultUseCache: UseCacheSchema = { export const DefaultUseCache: UseCacheSchema = {
@ -74,6 +80,7 @@ export const DefaultUseCache: UseCacheSchema = {
'chat.generating': false, 'chat.generating': false,
'chat.websearch.searching': false, 'chat.websearch.searching': false,
'chat.websearch.active_searches': {}, 'chat.websearch.active_searches': {},
'chat.active_view': 'topic',
// Minapp management // Minapp management
'minapp.opened_keep_alive': [], 'minapp.opened_keep_alive': [],
@ -84,7 +91,12 @@ export const DefaultUseCache: UseCacheSchema = {
// Topic management // Topic management
'topic.active': null, 'topic.active': null,
'topic.renaming': [], 'topic.renaming': [],
'topic.newly_renamed': [] 'topic.newly_renamed': [],
// Agent management
'agent.active_id': null,
'agent.session.active_id_map': {},
'agent.session.waiting_id_map': {}
} }
/** /**

View File

@ -2,6 +2,7 @@ import type { BodyForPath, QueryParamsForPath, ResponseForPath } from '@shared/d
import type { ConcreteApiPaths } from '@shared/data/api/apiSchemas' import type { ConcreteApiPaths } from '@shared/data/api/apiSchemas'
import type { PaginatedResponse } from '@shared/data/api/apiTypes' import type { PaginatedResponse } from '@shared/data/api/apiTypes'
import { useState } from 'react' import { useState } from 'react'
import type { KeyedMutator } from 'swr'
import useSWR, { useSWRConfig } from 'swr' import useSWR, { useSWRConfig } from 'swr'
import useSWRMutation from 'swr/mutation' import useSWRMutation from 'swr/mutation'
@ -118,6 +119,18 @@ function getFetcher<TPath extends ConcreteApiPaths>([path, query]: [TPath, Recor
* revalidateOnFocus: true * revalidateOnFocus: true
* } * }
* }) * })
*
* // Optimistic updates with mutate (bound to current key, no key needed)
* const { data, mutate } = useQuery(`/topics/${id}`)
*
* // Update cache immediately without revalidation
* await mutate({ ...data, title: 'New Title' }, false)
*
* // Update cache with function and revalidate
* await mutate(prev => ({ ...prev, count: prev.count + 1 }))
*
* // Just revalidate (refetch from server)
* await mutate()
* ``` * ```
*/ */
export function useQuery<TPath extends ConcreteApiPaths>( export function useQuery<TPath extends ConcreteApiPaths>(
@ -139,6 +152,8 @@ export function useQuery<TPath extends ConcreteApiPaths>(
error?: Error error?: Error
/** Function to manually refetch data */ /** Function to manually refetch data */
refetch: () => void refetch: () => void
/** SWR mutate function for optimistic updates */
mutate: KeyedMutator<ResponseForPath<TPath, 'GET'>>
} { } {
// Internal type conversion for SWR compatibility // Internal type conversion for SWR compatibility
const key = options?.enabled !== false ? buildSWRKey(path, options?.query as Record<string, any>) : null const key = options?.enabled !== false ? buildSWRKey(path, options?.query as Record<string, any>) : null
@ -160,7 +175,8 @@ export function useQuery<TPath extends ConcreteApiPaths>(
data, data,
loading: isLoading || isValidating, loading: isLoading || isValidating,
error: error as Error | undefined, error: error as Error | undefined,
refetch refetch,
mutate
} }
} }

View File

@ -1,8 +1,8 @@
import { useRuntime } from '../useRuntime' import { useCache } from '@renderer/data/hooks/useCache'
import { useAgent } from './useAgent' import { useAgent } from './useAgent'
export const useActiveAgent = () => { export const useActiveAgent = () => {
const { chat } = useRuntime() const [activeAgentId] = useCache('agent.active_id')
const { activeAgentId } = chat
return useAgent(activeAgentId) return useAgent(activeAgentId)
} }

View File

@ -1,9 +1,10 @@
import { useRuntime } from '../useRuntime' import { useCache } from '@renderer/data/hooks/useCache'
import { useSession } from './useSession' import { useSession } from './useSession'
export const useActiveSession = () => { export const useActiveSession = () => {
const { chat } = useRuntime() const [activeAgentId] = useCache('agent.active_id')
const { activeSessionIdMap, activeAgentId } = chat const [activeSessionIdMap] = useCache('agent.session.active_id_map')
const activeSessionId = activeAgentId ? activeSessionIdMap[activeAgentId] : null const activeSessionId = activeAgentId ? activeSessionIdMap[activeAgentId] : null
return useSession(activeAgentId, activeSessionId) return useSession(activeAgentId, activeSessionId)
} }

View File

@ -1,7 +1,6 @@
import { loggerService } from '@logger' import { loggerService } from '@logger'
import { useRuntime } from '@renderer/hooks/useRuntime' import { cacheService } from '@renderer/data/CacheService'
import { useAppDispatch } from '@renderer/store' import { useCache } from '@renderer/data/hooks/useCache'
import { setActiveSessionIdAction, setActiveTopicOrSessionAction } from '@renderer/store/runtime'
import { useCallback, useEffect } from 'react' import { useCallback, useEffect } from 'react'
import { useAgentClient } from './useAgentClient' import { useAgentClient } from './useAgentClient'
@ -14,10 +13,9 @@ const logger = loggerService.withContext('useAgentSessionInitializer')
* its most recent session is automatically selected. * its most recent session is automatically selected.
*/ */
export const useAgentSessionInitializer = () => { export const useAgentSessionInitializer = () => {
const dispatch = useAppDispatch()
const client = useAgentClient() const client = useAgentClient()
const { chat } = useRuntime() const [activeAgentId] = useCache('agent.active_id')
const { activeAgentId, activeSessionIdMap } = chat const [activeSessionIdMap] = useCache('agent.session.active_id_map')
/** /**
* Initialize session for the given agent by loading its sessions * Initialize session for the given agent by loading its sessions
@ -32,7 +30,7 @@ export const useAgentSessionInitializer = () => {
const currentSessionId = activeSessionIdMap[agentId] const currentSessionId = activeSessionIdMap[agentId]
if (currentSessionId) { if (currentSessionId) {
// Session already exists, just switch to session view // Session already exists, just switch to session view
dispatch(setActiveTopicOrSessionAction('session')) cacheService.set('chat.active_view', 'session')
return return
} }
@ -45,20 +43,21 @@ export const useAgentSessionInitializer = () => {
const latestSession = sessions[0] const latestSession = sessions[0]
// Set the latest session as active // Set the latest session as active
dispatch(setActiveSessionIdAction({ agentId, sessionId: latestSession.id })) const currentMap = cacheService.get('agent.session.active_id_map') ?? {}
dispatch(setActiveTopicOrSessionAction('session')) cacheService.set('agent.session.active_id_map', { ...currentMap, [agentId]: latestSession.id })
cacheService.set('chat.active_view', 'session')
} else { } else {
// No sessions exist, we might want to create one // No sessions exist, we might want to create one
// But for now, just switch to session view and let the Sessions component handle it // But for now, just switch to session view and let the Sessions component handle it
dispatch(setActiveTopicOrSessionAction('session')) cacheService.set('chat.active_view', 'session')
} }
} catch (error) { } catch (error) {
logger.error('Failed to initialize agent session:', error as Error) logger.error('Failed to initialize agent session:', error as Error)
// Even if loading fails, switch to session view // Even if loading fails, switch to session view
dispatch(setActiveTopicOrSessionAction('session')) cacheService.set('chat.active_view', 'session')
} }
}, },
[client, dispatch, activeSessionIdMap] [client, activeSessionIdMap]
) )
/** /**

View File

@ -1,5 +1,5 @@
import { useAppDispatch } from '@renderer/store' import { cacheService } from '@renderer/data/CacheService'
import { setActiveAgentId, setActiveSessionIdAction } from '@renderer/store/runtime' import { useCache } from '@renderer/data/hooks/useCache'
import type { AddAgentForm, CreateAgentResponse } from '@renderer/types' import type { AddAgentForm, CreateAgentResponse } from '@renderer/types'
import { formatErrorMessageWithPrefix } from '@renderer/utils/error' import { formatErrorMessageWithPrefix } from '@renderer/utils/error'
import { useCallback } from 'react' import { useCallback } from 'react'
@ -7,7 +7,6 @@ import { useTranslation } from 'react-i18next'
import useSWR from 'swr' import useSWR from 'swr'
import { useApiServer } from '../useApiServer' import { useApiServer } from '../useApiServer'
import { useRuntime } from '../useRuntime'
import { useAgentClient } from './useAgentClient' import { useAgentClient } from './useAgentClient'
type Result<T> = type Result<T> =
@ -43,9 +42,7 @@ export const useAgents = () => {
}, [apiServerConfig.enabled, apiServerRunning, client, t]) }, [apiServerConfig.enabled, apiServerRunning, client, t])
const { data, error, isLoading, mutate } = useSWR(swrKey, fetcher) const { data, error, isLoading, mutate } = useSWR(swrKey, fetcher)
const { chat } = useRuntime() const [activeAgentId] = useCache('agent.active_id')
const { activeAgentId } = chat
const dispatch = useAppDispatch()
const addAgent = useCallback( const addAgent = useCallback(
async (form: AddAgentForm): Promise<Result<CreateAgentResponse>> => { async (form: AddAgentForm): Promise<Result<CreateAgentResponse>> => {
@ -71,14 +68,11 @@ export const useAgents = () => {
async (id: string) => { async (id: string) => {
try { try {
await client.deleteAgent(id) await client.deleteAgent(id)
dispatch(setActiveSessionIdAction({ agentId: id, sessionId: null })) const currentMap = cacheService.get('agent.session.active_id_map') ?? {}
cacheService.set('agent.session.active_id_map', { ...currentMap, [id]: null })
if (activeAgentId === id) { if (activeAgentId === id) {
const newId = data?.filter((a) => a.id !== id).find(() => true)?.id const newId = data?.filter((a) => a.id !== id).find(() => true)?.id
if (newId) { cacheService.set('agent.active_id', newId ?? null)
dispatch(setActiveAgentId(newId))
} else {
dispatch(setActiveAgentId(null))
}
} }
mutate((prev) => prev?.filter((a) => a.id !== id) ?? []) mutate((prev) => prev?.filter((a) => a.id !== id) ?? [])
window.toast.success(t('common.delete_success')) window.toast.success(t('common.delete_success'))
@ -86,7 +80,7 @@ export const useAgents = () => {
window.toast.error(formatErrorMessageWithPrefix(error, t('agent.delete.error.failed'))) window.toast.error(formatErrorMessageWithPrefix(error, t('agent.delete.error.failed')))
} }
}, },
[activeAgentId, client, data, dispatch, mutate, t] [activeAgentId, client, data, mutate, t]
) )
const getAgent = useCallback( const getAgent = useCallback(

View File

@ -1,8 +1,7 @@
import { loggerService } from '@logger' import { loggerService } from '@logger'
import { cacheService } from '@renderer/data/CacheService'
import { useAgent } from '@renderer/hooks/agents/useAgent' import { useAgent } from '@renderer/hooks/agents/useAgent'
import { useSessions } from '@renderer/hooks/agents/useSessions' import { useSessions } from '@renderer/hooks/agents/useSessions'
import { useAppDispatch } from '@renderer/store'
import { setActiveSessionIdAction, setActiveTopicOrSessionAction } from '@renderer/store/runtime'
import type { CreateSessionForm } from '@renderer/types' import type { CreateSessionForm } from '@renderer/types'
import { useCallback, useState } from 'react' import { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
@ -15,7 +14,6 @@ const logger = loggerService.withContext('useCreateDefaultSession')
export const useCreateDefaultSession = (agentId: string | null) => { export const useCreateDefaultSession = (agentId: string | null) => {
const { agent } = useAgent(agentId) const { agent } = useAgent(agentId)
const { createSession } = useSessions(agentId) const { createSession } = useSessions(agentId)
const dispatch = useAppDispatch()
const { t } = useTranslation() const { t } = useTranslation()
const [creatingSession, setCreatingSession] = useState(false) const [creatingSession, setCreatingSession] = useState(false)
@ -35,8 +33,9 @@ export const useCreateDefaultSession = (agentId: string | null) => {
const created = await createSession(session) const created = await createSession(session)
if (created) { if (created) {
dispatch(setActiveSessionIdAction({ agentId, sessionId: created.id })) const currentMap = cacheService.get('agent.session.active_id_map') ?? {}
dispatch(setActiveTopicOrSessionAction('session')) cacheService.set('agent.session.active_id_map', { ...currentMap, [agentId]: created.id })
cacheService.set('chat.active_view', 'session')
} }
return created return created
@ -46,7 +45,7 @@ export const useCreateDefaultSession = (agentId: string | null) => {
} finally { } finally {
setCreatingSession(false) setCreatingSession(false)
} }
}, [agentId, agent, createSession, creatingSession, dispatch, t]) }, [agentId, agent, createSession, creatingSession, t])
return { return {
createDefaultSession, createDefaultSession,

View File

@ -1,9 +0,0 @@
/**
* Data Refactor, notes by fullex
* //TODO @deprecated this file will be removed
*/
import { useAppSelector } from '@renderer/store'
export function useRuntime() {
return useAppSelector((state) => state.runtime)
}

View File

@ -6,10 +6,10 @@ import { ContentSearch } from '@renderer/components/ContentSearch'
import MultiSelectActionPopup from '@renderer/components/Popups/MultiSelectionPopup' import MultiSelectActionPopup from '@renderer/components/Popups/MultiSelectionPopup'
import PromptPopup from '@renderer/components/Popups/PromptPopup' import PromptPopup from '@renderer/components/Popups/PromptPopup'
import { QuickPanelProvider } from '@renderer/components/QuickPanel' import { QuickPanelProvider } from '@renderer/components/QuickPanel'
import { useCache } from '@renderer/data/hooks/useCache'
import { useCreateDefaultSession } from '@renderer/hooks/agents/useCreateDefaultSession' import { useCreateDefaultSession } from '@renderer/hooks/agents/useCreateDefaultSession'
import { useAssistant } from '@renderer/hooks/useAssistant' import { useAssistant } from '@renderer/hooks/useAssistant'
import { useChatContext } from '@renderer/hooks/useChatContext' import { useChatContext } from '@renderer/hooks/useChatContext'
import { useRuntime } from '@renderer/hooks/useRuntime'
import { useSettings } from '@renderer/hooks/useSettings' import { useSettings } from '@renderer/hooks/useSettings'
import { useShortcut } from '@renderer/hooks/useShortcuts' import { useShortcut } from '@renderer/hooks/useShortcuts'
import { useShowAssistants, useShowTopics } from '@renderer/hooks/useStore' import { useShowAssistants, useShowTopics } from '@renderer/hooks/useStore'
@ -54,8 +54,9 @@ const Chat: FC<Props> = (props) => {
const { isMultiSelectMode } = useChatContext(props.activeTopic) const { isMultiSelectMode } = useChatContext(props.activeTopic)
const [isTopNavbar] = usePreference('ui.navbar.position') const [isTopNavbar] = usePreference('ui.navbar.position')
const chatMaxWidth = useChatMaxWidth() const chatMaxWidth = useChatMaxWidth()
const { chat } = useRuntime() const [activeAgentId] = useCache('agent.active_id')
const { activeTopicOrSession, activeAgentId, activeSessionIdMap } = chat const [activeTopicOrSession] = useCache('chat.active_view')
const [activeSessionIdMap] = useCache('agent.session.active_id_map')
const activeSessionId = activeAgentId ? activeSessionIdMap[activeAgentId] : null const activeSessionId = activeAgentId ? activeSessionIdMap[activeAgentId] : null
const sessionAgentId = activeTopicOrSession === 'session' ? activeAgentId : null const sessionAgentId = activeTopicOrSession === 'session' ? activeAgentId : null
const { createDefaultSession } = useCreateDefaultSession(sessionAgentId) const { createDefaultSession } = useCreateDefaultSession(sessionAgentId)

View File

@ -1,13 +1,13 @@
import { usePreference } from '@data/hooks/usePreference' import { usePreference } from '@data/hooks/usePreference'
import { ErrorBoundary } from '@renderer/components/ErrorBoundary' import { ErrorBoundary } from '@renderer/components/ErrorBoundary'
import { cacheService } from '@renderer/data/CacheService'
import { useCache } from '@renderer/data/hooks/useCache'
import { useAgentSessionInitializer } from '@renderer/hooks/agents/useAgentSessionInitializer' import { useAgentSessionInitializer } from '@renderer/hooks/agents/useAgentSessionInitializer'
import { useAssistants } from '@renderer/hooks/useAssistant' import { useAssistants } from '@renderer/hooks/useAssistant'
import { useNavbarPosition } from '@renderer/hooks/useNavbar' import { useNavbarPosition } from '@renderer/hooks/useNavbar'
import { useRuntime } from '@renderer/hooks/useRuntime'
import { useActiveTopic } from '@renderer/hooks/useTopic' import { useActiveTopic } from '@renderer/hooks/useTopic'
import NavigationService from '@renderer/services/NavigationService' import NavigationService from '@renderer/services/NavigationService'
import { newMessagesActions } from '@renderer/store/newMessage' import { newMessagesActions } from '@renderer/store/newMessage'
import { setActiveAgentId, setActiveTopicOrSessionAction } from '@renderer/store/runtime'
import type { Assistant, Topic } from '@renderer/types' import type { Assistant, Topic } from '@renderer/types'
import { MIN_WINDOW_HEIGHT, MIN_WINDOW_WIDTH, SECOND_MIN_WINDOW_WIDTH } from '@shared/config/constant' import { MIN_WINDOW_HEIGHT, MIN_WINDOW_WIDTH, SECOND_MIN_WINDOW_WIDTH } from '@shared/config/constant'
import { useNavigate, useSearch } from '@tanstack/react-router' import { useNavigate, useSearch } from '@tanstack/react-router'
@ -52,8 +52,7 @@ const HomePage: FC = () => {
const [showTopics] = usePreference('topic.tab.show') const [showTopics] = usePreference('topic.tab.show')
const [topicPosition] = usePreference('topic.position') const [topicPosition] = usePreference('topic.position')
const dispatch = useDispatch() const dispatch = useDispatch()
const { chat } = useRuntime() const [activeTopicOrSession, setActiveTopicOrSession] = useCache('chat.active_view')
const { activeTopicOrSession } = chat
_activeAssistant = activeAssistant _activeAssistant = activeAssistant
@ -64,14 +63,14 @@ const HomePage: FC = () => {
startTransition(() => { startTransition(() => {
_setActiveAssistant(newAssistant) _setActiveAssistant(newAssistant)
if (newAssistant.id !== 'fake') { if (newAssistant.id !== 'fake') {
dispatch(setActiveAgentId(null)) cacheService.set('agent.active_id', null)
} }
// 同步更新 active topic避免不必要的重新渲染 // 同步更新 active topic避免不必要的重新渲染
const newTopic = newAssistant.topics[0] const newTopic = newAssistant.topics[0]
_setActiveTopic((prev) => (newTopic?.id === prev.id ? prev : newTopic)) _setActiveTopic((prev) => (newTopic?.id === prev.id ? prev : newTopic))
}) })
}, },
[_setActiveTopic, activeAssistant?.id, dispatch] [_setActiveTopic, activeAssistant?.id]
) )
const setActiveTopic = useCallback( const setActiveTopic = useCallback(
@ -79,10 +78,10 @@ const HomePage: FC = () => {
startTransition(() => { startTransition(() => {
_setActiveTopic((prev) => (newTopic?.id === prev.id ? prev : newTopic)) _setActiveTopic((prev) => (newTopic?.id === prev.id ? prev : newTopic))
dispatch(newMessagesActions.setTopicFulfilled({ topicId: newTopic.id, fulfilled: false })) dispatch(newMessagesActions.setTopicFulfilled({ topicId: newTopic.id, fulfilled: false }))
dispatch(setActiveTopicOrSessionAction('topic')) setActiveTopicOrSession('topic')
}) })
}, },
[_setActiveTopic, dispatch] [_setActiveTopic, dispatch, setActiveTopicOrSession]
) )
useEffect(() => { useEffect(() => {

View File

@ -10,6 +10,7 @@ import {
isVisionModels, isVisionModels,
isWebSearchModel isWebSearchModel
} from '@renderer/config/models' } from '@renderer/config/models'
import { useCache } from '@renderer/data/hooks/useCache'
import db from '@renderer/databases' import db from '@renderer/databases'
import { useAssistant } from '@renderer/hooks/useAssistant' import { useAssistant } from '@renderer/hooks/useAssistant'
import { useInputText } from '@renderer/hooks/useInputText' import { useInputText } from '@renderer/hooks/useInputText'
@ -30,7 +31,7 @@ import { checkRateLimit, getUserMessage } from '@renderer/services/MessagesServi
import { spanManagerService } from '@renderer/services/SpanManagerService' import { spanManagerService } from '@renderer/services/SpanManagerService'
import { estimateTextTokens as estimateTxtTokens, estimateUserPromptUsage } from '@renderer/services/TokenService' import { estimateTextTokens as estimateTxtTokens, estimateUserPromptUsage } from '@renderer/services/TokenService'
import WebSearchService from '@renderer/services/WebSearchService' import WebSearchService from '@renderer/services/WebSearchService'
import { useAppDispatch, useAppSelector } from '@renderer/store' import { useAppDispatch } from '@renderer/store'
import { sendMessage as _sendMessage } from '@renderer/store/thunk/messageThunk' import { sendMessage as _sendMessage } from '@renderer/store/thunk/messageThunk'
import { type Assistant, type FileType, type KnowledgeBase, type Model, type Topic, TopicType } from '@renderer/types' import { type Assistant, type FileType, type KnowledgeBase, type Model, type Topic, TopicType } from '@renderer/types'
import type { MessageInputBaseParams } from '@renderer/types/newMessage' import type { MessageInputBaseParams } from '@renderer/types/newMessage'
@ -165,7 +166,7 @@ const InputbarInner: FC<InputbarInnerProps> = ({ assistant: initialAssistant, se
const isVisionAssistant = useMemo(() => isVisionModel(model), [model]) const isVisionAssistant = useMemo(() => isVisionModel(model), [model])
const isGenerateImageAssistant = useMemo(() => isGenerateImageModel(model), [model]) const isGenerateImageAssistant = useMemo(() => isGenerateImageModel(model), [model])
const { setTimeoutTimer } = useTimer() const { setTimeoutTimer } = useTimer()
const isMultiSelectMode = useAppSelector((state) => state.runtime.chat.isMultiSelectMode) const [isMultiSelectMode] = useCache('chat.multi_select_mode')
const isVisionSupported = useMemo( const isVisionSupported = useMemo(
() => () =>

View File

@ -5,11 +5,11 @@ import UserPopup from '@renderer/components/Popups/UserPopup'
import { APP_NAME, AppLogo, isLocalAi } from '@renderer/config/env' import { APP_NAME, AppLogo, isLocalAi } from '@renderer/config/env'
import { getModelLogoById } from '@renderer/config/models' import { getModelLogoById } from '@renderer/config/models'
import { useTheme } from '@renderer/context/ThemeProvider' import { useTheme } from '@renderer/context/ThemeProvider'
import { useCache } from '@renderer/data/hooks/useCache'
import { useAgent } from '@renderer/hooks/agents/useAgent' import { useAgent } from '@renderer/hooks/agents/useAgent'
import useAvatar from '@renderer/hooks/useAvatar' import useAvatar from '@renderer/hooks/useAvatar'
import { useChatContext } from '@renderer/hooks/useChatContext' import { useChatContext } from '@renderer/hooks/useChatContext'
import { useMinappPopup } from '@renderer/hooks/useMinappPopup' import { useMinappPopup } from '@renderer/hooks/useMinappPopup'
import { useRuntime } from '@renderer/hooks/useRuntime'
import { useMessageStyle } from '@renderer/hooks/useSettings' import { useMessageStyle } from '@renderer/hooks/useSettings'
import { useSidebarIconShow } from '@renderer/hooks/useSidebarIcon' import { useSidebarIconShow } from '@renderer/hooks/useSidebarIcon'
import { getMessageModelId } from '@renderer/services/MessagesService' import { getMessageModelId } from '@renderer/services/MessagesService'
@ -43,8 +43,8 @@ const MessageHeader: FC<Props> = memo(({ assistant, model, message, topic, isGro
const { theme } = useTheme() const { theme } = useTheme()
const [userName] = usePreference('app.user.name') const [userName] = usePreference('app.user.name')
const showMinappIcon = useSidebarIconShow('minapp') const showMinappIcon = useSidebarIconShow('minapp')
const { chat } = useRuntime() const [activeAgentId] = useCache('agent.active_id')
const { activeTopicOrSession, activeAgentId } = chat const [activeTopicOrSession] = useCache('chat.active_view')
const { agent } = useAgent(activeAgentId) const { agent } = useAgent(activeAgentId)
const isAgentView = activeTopicOrSession === 'session' const isAgentView = activeTopicOrSession === 'session'
const { t } = useTranslation() const { t } = useTranslation()

View File

@ -1,9 +1,9 @@
import Scrollbar from '@renderer/components/Scrollbar' import Scrollbar from '@renderer/components/Scrollbar'
import { useCache } from '@renderer/data/hooks/useCache'
import { useAgents } from '@renderer/hooks/agents/useAgents' import { useAgents } from '@renderer/hooks/agents/useAgents'
import { useApiServer } from '@renderer/hooks/useApiServer' import { useApiServer } from '@renderer/hooks/useApiServer'
import { useAssistants } from '@renderer/hooks/useAssistant' import { useAssistants } from '@renderer/hooks/useAssistant'
import { useAssistantPresets } from '@renderer/hooks/useAssistantPresets' import { useAssistantPresets } from '@renderer/hooks/useAssistantPresets'
import { useRuntime } from '@renderer/hooks/useRuntime'
import { useAssistantsTabSortType } from '@renderer/hooks/useStore' import { useAssistantsTabSortType } from '@renderer/hooks/useStore'
import { useTags } from '@renderer/hooks/useTags' import { useTags } from '@renderer/hooks/useTags'
import type { Assistant, Topic } from '@renderer/types' import type { Assistant, Topic } from '@renderer/types'
@ -32,11 +32,10 @@ const AssistantsTab: FC<AssistantsTabProps> = (props) => {
const containerRef = useRef<HTMLDivElement>(null) const containerRef = useRef<HTMLDivElement>(null)
const { apiServerConfig } = useApiServer() const { apiServerConfig } = useApiServer()
const apiServerEnabled = apiServerConfig.enabled const apiServerEnabled = apiServerConfig.enabled
const { chat } = useRuntime()
// Agent related hooks // Agent related hooks
const { agents, deleteAgent, isLoading: agentsLoading, error: agentsError } = useAgents() const { agents, deleteAgent, isLoading: agentsLoading, error: agentsError } = useAgents()
const { activeAgentId } = chat const [activeAgentId] = useCache('agent.active_id')
const { setActiveAgentId } = useActiveAgent() const { setActiveAgentId } = useActiveAgent()
// Assistant related hooks // Assistant related hooks

View File

@ -1,4 +1,4 @@
import { useRuntime } from '@renderer/hooks/useRuntime' import { useCache } from '@renderer/data/hooks/useCache'
import { useSettings } from '@renderer/hooks/useSettings' import { useSettings } from '@renderer/hooks/useSettings'
import { cn } from '@renderer/utils' import { cn } from '@renderer/utils'
import { Alert } from 'antd' import { Alert } from 'antd'
@ -11,8 +11,7 @@ import Sessions from './components/Sessions'
interface SessionsTabProps {} interface SessionsTabProps {}
const SessionsTab: FC<SessionsTabProps> = () => { const SessionsTab: FC<SessionsTabProps> = () => {
const { chat } = useRuntime() const [activeAgentId] = useCache('agent.active_id')
const { activeAgentId } = chat
const { t } = useTranslation() const { t } = useTranslation()
const { apiServer } = useSettings() const { apiServer } = useSettings()

View File

@ -1,4 +1,4 @@
import { useRuntime } from '@renderer/hooks/useRuntime' import { useCache } from '@renderer/data/hooks/useCache'
import type { Assistant, Topic } from '@renderer/types' import type { Assistant, Topic } from '@renderer/types'
import type { FC } from 'react' import type { FC } from 'react'
@ -15,8 +15,7 @@ interface Props {
} }
const TopicsTab: FC<Props> = (props) => { const TopicsTab: FC<Props> = (props) => {
const { chat } = useRuntime() const [activeTopicOrSession] = useCache('chat.active_view')
const { activeTopicOrSession } = chat
if (activeTopicOrSession === 'topic') { if (activeTopicOrSession === 'topic') {
return <Topics {...props} /> return <Topics {...props} />
} }

View File

@ -3,13 +3,12 @@ import ModelAvatar from '@renderer/components/Avatar/ModelAvatar'
import EmojiIcon from '@renderer/components/EmojiIcon' import EmojiIcon from '@renderer/components/EmojiIcon'
import { CopyIcon, DeleteIcon, EditIcon } from '@renderer/components/Icons' import { CopyIcon, DeleteIcon, EditIcon } from '@renderer/components/Icons'
import PromptPopup from '@renderer/components/Popups/PromptPopup' import PromptPopup from '@renderer/components/Popups/PromptPopup'
import { cacheService } from '@renderer/data/CacheService'
import { useAssistant, useAssistants } from '@renderer/hooks/useAssistant' import { useAssistant, useAssistants } from '@renderer/hooks/useAssistant'
import { useTags } from '@renderer/hooks/useTags' import { useTags } from '@renderer/hooks/useTags'
import AssistantSettingsPopup from '@renderer/pages/settings/AssistantSettings' import AssistantSettingsPopup from '@renderer/pages/settings/AssistantSettings'
import { getDefaultModel } from '@renderer/services/AssistantService' import { getDefaultModel } from '@renderer/services/AssistantService'
import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService' import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
import { useAppDispatch } from '@renderer/store'
import { setActiveTopicOrSessionAction } from '@renderer/store/runtime'
import type { Assistant } from '@renderer/types' import type { Assistant } from '@renderer/types'
import { cn, getLeadingEmoji, uuid } from '@renderer/utils' import { cn, getLeadingEmoji, uuid } from '@renderer/utils'
import { hasTopicPendingRequests } from '@renderer/utils/queue' import { hasTopicPendingRequests } from '@renderer/utils/queue'
@ -75,7 +74,6 @@ const AssistantItem: FC<AssistantItemProps> = ({
const { assistants, updateAssistants } = useAssistants() const { assistants, updateAssistants } = useAssistants()
const [isPending, setIsPending] = useState(false) const [isPending, setIsPending] = useState(false)
const dispatch = useAppDispatch()
useEffect(() => { useEffect(() => {
if (isActive) { if (isActive) {
@ -145,8 +143,8 @@ const AssistantItem: FC<AssistantItemProps> = ({
} }
} }
onSwitch(assistant) onSwitch(assistant)
dispatch(setActiveTopicOrSessionAction('topic')) cacheService.set('chat.active_view', 'topic')
}, [clickAssistantToShowTopic, onSwitch, assistant, dispatch, topicPosition]) }, [clickAssistantToShowTopic, onSwitch, assistant, topicPosition])
const assistantName = useMemo(() => assistant.name || t('chat.default.name'), [assistant.name, t]) const assistantName = useMemo(() => assistant.name || t('chat.default.name'), [assistant.name, t])
const fullAssistantName = useMemo( const fullAssistantName = useMemo(

View File

@ -2,9 +2,9 @@ import { Tooltip } from '@cherrystudio/ui'
import { usePreference } from '@data/hooks/usePreference' import { usePreference } from '@data/hooks/usePreference'
import { DeleteIcon, EditIcon } from '@renderer/components/Icons' import { DeleteIcon, EditIcon } from '@renderer/components/Icons'
import { isMac } from '@renderer/config/constant' import { isMac } from '@renderer/config/constant'
import { useCache } from '@renderer/data/hooks/useCache'
import { useUpdateSession } from '@renderer/hooks/agents/useUpdateSession' import { useUpdateSession } from '@renderer/hooks/agents/useUpdateSession'
import { useInPlaceEdit } from '@renderer/hooks/useInPlaceEdit' import { useInPlaceEdit } from '@renderer/hooks/useInPlaceEdit'
import { useRuntime } from '@renderer/hooks/useRuntime'
import { useTimer } from '@renderer/hooks/useTimer' import { useTimer } from '@renderer/hooks/useTimer'
import { SessionSettingsPopup } from '@renderer/pages/settings/AgentSettings' import { SessionSettingsPopup } from '@renderer/pages/settings/AgentSettings'
import { SessionLabel } from '@renderer/pages/settings/AgentSettings/shared' import { SessionLabel } from '@renderer/pages/settings/AgentSettings/shared'
@ -34,9 +34,9 @@ interface SessionItemProps {
const SessionItem: FC<SessionItemProps> = ({ session, agentId, onDelete, onPress }) => { const SessionItem: FC<SessionItemProps> = ({ session, agentId, onDelete, onPress }) => {
const { t } = useTranslation() const { t } = useTranslation()
const { chat } = useRuntime() const [activeSessionIdMap] = useCache('agent.session.active_id_map')
const { updateSession } = useUpdateSession(agentId) const { updateSession } = useUpdateSession(agentId)
const activeSessionId = chat.activeSessionIdMap[agentId] const activeSessionId = activeSessionIdMap[agentId]
const [isConfirmingDeletion, setIsConfirmingDeletion] = useState(false) const [isConfirmingDeletion, setIsConfirmingDeletion] = useState(false)
const { setTimeoutTimer } = useTimer() const { setTimeoutTimer } = useTimer()
const [_targetSession, setTargetSession] = useState<AgentSessionEntity>(session) const [_targetSession, setTargetSession] = useState<AgentSessionEntity>(session)

View File

@ -1,14 +1,10 @@
import { DynamicVirtualList } from '@renderer/components/VirtualList' import { DynamicVirtualList } from '@renderer/components/VirtualList'
import { cacheService } from '@renderer/data/CacheService'
import { useCache } from '@renderer/data/hooks/useCache'
import { useCreateDefaultSession } from '@renderer/hooks/agents/useCreateDefaultSession' import { useCreateDefaultSession } from '@renderer/hooks/agents/useCreateDefaultSession'
import { useSessions } from '@renderer/hooks/agents/useSessions' import { useSessions } from '@renderer/hooks/agents/useSessions'
import { useRuntime } from '@renderer/hooks/useRuntime'
import { useAppDispatch } from '@renderer/store' import { useAppDispatch } from '@renderer/store'
import { newMessagesActions } from '@renderer/store/newMessage' import { newMessagesActions } from '@renderer/store/newMessage'
import {
setActiveSessionIdAction,
setActiveTopicOrSessionAction,
setSessionWaitingAction
} from '@renderer/store/runtime'
import { buildAgentSessionTopicId } from '@renderer/utils/agentSession' import { buildAgentSessionTopicId } from '@renderer/utils/agentSession'
import { Alert, Spin } from 'antd' import { Alert, Spin } from 'antd'
import { motion } from 'framer-motion' import { motion } from 'framer-motion'
@ -28,18 +24,15 @@ interface SessionsProps {
const Sessions: React.FC<SessionsProps> = ({ agentId }) => { const Sessions: React.FC<SessionsProps> = ({ agentId }) => {
const { t } = useTranslation() const { t } = useTranslation()
const { sessions, isLoading, error, deleteSession } = useSessions(agentId) const { sessions, isLoading, error, deleteSession } = useSessions(agentId)
const { chat } = useRuntime() const [activeSessionIdMap] = useCache('agent.session.active_id_map')
const { activeSessionIdMap } = chat
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
const { createDefaultSession, creatingSession } = useCreateDefaultSession(agentId) const { createDefaultSession, creatingSession } = useCreateDefaultSession(agentId)
const setActiveSessionId = useCallback( const setActiveSessionId = useCallback((agentId: string, sessionId: string | null) => {
(agentId: string, sessionId: string | null) => { const currentMap = cacheService.get('agent.session.active_id_map') ?? {}
dispatch(setActiveSessionIdAction({ agentId, sessionId })) cacheService.set('agent.session.active_id_map', { ...currentMap, [agentId]: sessionId })
dispatch(setActiveTopicOrSessionAction('session')) cacheService.set('chat.active_view', 'session')
}, }, [])
[dispatch]
)
const handleDeleteSession = useCallback( const handleDeleteSession = useCallback(
async (id: string) => { async (id: string) => {
@ -47,19 +40,22 @@ const Sessions: React.FC<SessionsProps> = ({ agentId }) => {
window.toast.error(t('agent.session.delete.error.last')) window.toast.error(t('agent.session.delete.error.last'))
return return
} }
dispatch(setSessionWaitingAction({ id, value: true })) const waitingMap = cacheService.get('agent.session.waiting_id_map') ?? {}
cacheService.set('agent.session.waiting_id_map', { ...waitingMap, [id]: true })
const success = await deleteSession(id) const success = await deleteSession(id)
if (success) { if (success) {
const newSessionId = sessions.find((s) => s.id !== id)?.id const newSessionId = sessions.find((s) => s.id !== id)?.id
if (newSessionId) { if (newSessionId) {
dispatch(setActiveSessionIdAction({ agentId, sessionId: newSessionId })) const currentMap = cacheService.get('agent.session.active_id_map') ?? {}
cacheService.set('agent.session.active_id_map', { ...currentMap, [agentId]: newSessionId })
} else { } else {
// may clear messages instead of forbidden deletion // may clear messages instead of forbidden deletion
} }
} }
dispatch(setSessionWaitingAction({ id, value: false })) const updatedMap = cacheService.get('agent.session.waiting_id_map') ?? {}
cacheService.set('agent.session.waiting_id_map', { ...updatedMap, [id]: false })
}, },
[agentId, deleteSession, dispatch, sessions, t] [agentId, deleteSession, sessions, t]
) )
const activeSessionId = activeSessionIdMap[agentId] const activeSessionId = activeSessionIdMap[agentId]

View File

@ -74,10 +74,10 @@ export const Topics: React.FC<Props> = ({ assistant: _assistant, activeTopic, se
const [, setGenerating] = useCache('chat.generating') const [, setGenerating] = useCache('chat.generating')
const renamingTopics = useSelector((state: RootState) => state.runtime.chat.renamingTopics) const [renamingTopics] = useCache('topic.renaming')
const topicLoadingQuery = useSelector((state: RootState) => state.messages.loadingByTopic) const topicLoadingQuery = useSelector((state: RootState) => state.messages.loadingByTopic)
const topicFulfilledQuery = useSelector((state: RootState) => state.messages.fulfilledByTopic) const topicFulfilledQuery = useSelector((state: RootState) => state.messages.fulfilledByTopic)
const newlyRenamedTopics = useSelector((state: RootState) => state.runtime.chat.newlyRenamedTopics) const [newlyRenamedTopics] = useCache('topic.newly_renamed')
const borderRadius = showTopicTime ? 12 : 'var(--list-item-border-radius)' const borderRadius = showTopicTime ? 12 : 'var(--list-item-border-radius)'

View File

@ -1,8 +1,7 @@
import AddAssistantOrAgentPopup from '@renderer/components/Popups/AddAssistantOrAgentPopup' import AddAssistantOrAgentPopup from '@renderer/components/Popups/AddAssistantOrAgentPopup'
import AgentModalPopup from '@renderer/components/Popups/agent/AgentModal' import AgentModalPopup from '@renderer/components/Popups/agent/AgentModal'
import { cacheService } from '@renderer/data/CacheService'
import { useApiServer } from '@renderer/hooks/useApiServer' import { useApiServer } from '@renderer/hooks/useApiServer'
import { useAppDispatch } from '@renderer/store'
import { setActiveTopicOrSessionAction } from '@renderer/store/runtime'
import type { AgentEntity, Assistant, Topic } from '@renderer/types' import type { AgentEntity, Assistant, Topic } from '@renderer/types'
import type { FC } from 'react' import type { FC } from 'react'
import { useCallback } from 'react' import { useCallback } from 'react'
@ -18,7 +17,6 @@ interface UnifiedAddButtonProps {
const UnifiedAddButton: FC<UnifiedAddButtonProps> = ({ onCreateAssistant, setActiveAssistant, setActiveAgentId }) => { const UnifiedAddButton: FC<UnifiedAddButtonProps> = ({ onCreateAssistant, setActiveAssistant, setActiveAgentId }) => {
const { t } = useTranslation() const { t } = useTranslation()
const dispatch = useAppDispatch()
const { apiServerRunning, startApiServer } = useApiServer() const { apiServerRunning, startApiServer } = useApiServer()
const afterCreate = useCallback( const afterCreate = useCallback(
@ -41,9 +39,9 @@ const UnifiedAddButton: FC<UnifiedAddButtonProps> = ({ onCreateAssistant, setAct
type: 'chat' type: 'chat'
}) })
setActiveAgentId(a.id) setActiveAgentId(a.id)
dispatch(setActiveTopicOrSessionAction('session')) cacheService.set('chat.active_view', 'session')
}, },
[dispatch, setActiveAgentId, setActiveAssistant] [setActiveAgentId, setActiveAssistant]
) )
const handleAddButtonClick = async () => { const handleAddButtonClick = async () => {

View File

@ -1,18 +1,16 @@
import { cacheService } from '@renderer/data/CacheService'
import { useAgentSessionInitializer } from '@renderer/hooks/agents/useAgentSessionInitializer' import { useAgentSessionInitializer } from '@renderer/hooks/agents/useAgentSessionInitializer'
import { useAppDispatch } from '@renderer/store'
import { setActiveAgentId as setActiveAgentIdAction } from '@renderer/store/runtime'
import { useCallback } from 'react' import { useCallback } from 'react'
export const useActiveAgent = () => { export const useActiveAgent = () => {
const dispatch = useAppDispatch()
const { initializeAgentSession } = useAgentSessionInitializer() const { initializeAgentSession } = useAgentSessionInitializer()
const setActiveAgentId = useCallback( const setActiveAgentId = useCallback(
async (id: string) => { async (id: string) => {
dispatch(setActiveAgentIdAction(id)) cacheService.set('agent.active_id', id)
await initializeAgentSession(id) await initializeAgentSession(id)
}, },
[dispatch, initializeAgentSession] [initializeAgentSession]
) )
return { setActiveAgentId } return { setActiveAgentId }

View File

@ -1,14 +1,12 @@
import { usePreference } from '@data/hooks/usePreference' import { usePreference } from '@data/hooks/usePreference'
import AddAssistantPopup from '@renderer/components/Popups/AddAssistantPopup' import AddAssistantPopup from '@renderer/components/Popups/AddAssistantPopup'
import { useCache } from '@renderer/data/hooks/useCache'
import { useActiveSession } from '@renderer/hooks/agents/useActiveSession' import { useActiveSession } from '@renderer/hooks/agents/useActiveSession'
import { useUpdateSession } from '@renderer/hooks/agents/useUpdateSession' import { useUpdateSession } from '@renderer/hooks/agents/useUpdateSession'
import { useAssistants, useDefaultAssistant } from '@renderer/hooks/useAssistant' import { useAssistants, useDefaultAssistant } from '@renderer/hooks/useAssistant'
import { useNavbarPosition } from '@renderer/hooks/useNavbar' import { useNavbarPosition } from '@renderer/hooks/useNavbar'
import { useRuntime } from '@renderer/hooks/useRuntime'
import { useShowTopics } from '@renderer/hooks/useStore' import { useShowTopics } from '@renderer/hooks/useStore'
import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService' import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
import { useAppDispatch } from '@renderer/store'
import { setActiveAgentId, setActiveTopicOrSessionAction } from '@renderer/store/runtime'
import type { Assistant, Topic } from '@renderer/types' import type { Assistant, Topic } from '@renderer/types'
import type { Tab } from '@renderer/types/chat' import type { Tab } from '@renderer/types/chat'
import { classNames, getErrorMessage, uuid } from '@renderer/utils' import { classNames, getErrorMessage, uuid } from '@renderer/utils'
@ -50,11 +48,10 @@ const HomeTabs: FC<Props> = ({
const { toggleShowTopics } = useShowTopics() const { toggleShowTopics } = useShowTopics()
const { isLeftNavbar } = useNavbarPosition() const { isLeftNavbar } = useNavbarPosition()
const { t } = useTranslation() const { t } = useTranslation()
const { chat } = useRuntime() const [activeAgentId, setActiveAgentId] = useCache('agent.active_id')
const { activeTopicOrSession, activeAgentId } = chat const [activeTopicOrSession, setActiveTopicOrSession] = useCache('chat.active_view')
const { session, isLoading: isSessionLoading, error: sessionError } = useActiveSession() const { session, isLoading: isSessionLoading, error: sessionError } = useActiveSession()
const { updateSession } = useUpdateSession(activeAgentId) const { updateSession } = useUpdateSession(activeAgentId)
const dispatch = useAppDispatch()
const isSessionView = activeTopicOrSession === 'session' const isSessionView = activeTopicOrSession === 'session'
const isTopicView = activeTopicOrSession === 'topic' const isTopicView = activeTopicOrSession === 'topic'
@ -76,8 +73,8 @@ const HomeTabs: FC<Props> = ({
const assistant = await AddAssistantPopup.show() const assistant = await AddAssistantPopup.show()
if (assistant) { if (assistant) {
setActiveAssistant(assistant) setActiveAssistant(assistant)
dispatch(setActiveAgentId(null)) setActiveAgentId(null)
dispatch(setActiveTopicOrSessionAction('topic')) setActiveTopicOrSession('topic')
} }
} }
@ -85,8 +82,8 @@ const HomeTabs: FC<Props> = ({
const assistant = { ...defaultAssistant, id: uuid() } const assistant = { ...defaultAssistant, id: uuid() }
addAssistant(assistant) addAssistant(assistant)
setActiveAssistant(assistant) setActiveAssistant(assistant)
dispatch(setActiveAgentId(null)) setActiveAgentId(null)
dispatch(setActiveTopicOrSessionAction('topic')) setActiveTopicOrSession('topic')
} }
useEffect(() => { useEffect(() => {

View File

@ -1,8 +1,8 @@
import HorizontalScrollContainer from '@renderer/components/HorizontalScrollContainer' import HorizontalScrollContainer from '@renderer/components/HorizontalScrollContainer'
import { useCache } from '@renderer/data/hooks/useCache'
import { useActiveAgent } from '@renderer/hooks/agents/useActiveAgent' import { useActiveAgent } from '@renderer/hooks/agents/useActiveAgent'
import { useActiveSession } from '@renderer/hooks/agents/useActiveSession' import { useActiveSession } from '@renderer/hooks/agents/useActiveSession'
import { useUpdateSession } from '@renderer/hooks/agents/useUpdateSession' import { useUpdateSession } from '@renderer/hooks/agents/useUpdateSession'
import { useRuntime } from '@renderer/hooks/useRuntime'
import type { AgentEntity, AgentSessionEntity, ApiModel, Assistant } from '@renderer/types' import type { AgentEntity, AgentSessionEntity, ApiModel, Assistant } from '@renderer/types'
import { formatErrorMessageWithPrefix } from '@renderer/utils/error' import { formatErrorMessageWithPrefix } from '@renderer/utils/error'
import { t } from 'i18next' import { t } from 'i18next'
@ -23,8 +23,7 @@ interface Props {
} }
const ChatNavbarContent: FC<Props> = ({ assistant }) => { const ChatNavbarContent: FC<Props> = ({ assistant }) => {
const { chat } = useRuntime() const [activeTopicOrSession] = useCache('chat.active_view')
const { activeTopicOrSession } = chat
const { agent: activeAgent } = useActiveAgent() const { agent: activeAgent } = useActiveAgent()
const { session: activeSession } = useActiveSession() const { session: activeSession } = useActiveSession()
const { updateModel } = useUpdateSession(activeAgent?.id ?? null) const { updateModel } = useUpdateSession(activeAgent?.id ?? null)

View File

@ -3,43 +3,41 @@
* //TODO @deprecated this file will be removed * //TODO @deprecated this file will be removed
*/ */
import type { PayloadAction } from '@reduxjs/toolkit'
import { createSlice } from '@reduxjs/toolkit' import { createSlice } from '@reduxjs/toolkit'
import type { Topic, WebSearchStatus } from '@renderer/types' // import type { Topic, WebSearchStatus } from '@renderer/types'
import type { UpdateInfo } from 'builder-util-runtime'
export interface ChatState { // export interface ChatState {
isMultiSelectMode: boolean // isMultiSelectMode: boolean
selectedMessageIds: string[] // selectedMessageIds: string[]
activeTopic: Topic | null // activeTopic: Topic | null
/** UI state. null represents no active agent */ // /** UI state. null represents no active agent */
activeAgentId: string | null // activeAgentId: string | null
/** UI state. Map agent id to active session id. // /** UI state. Map agent id to active session id.
* null represents no active session */ // * null represents no active session */
activeSessionIdMap: Record<string, string | null> // activeSessionIdMap: Record<string, string | null>
/** meanwhile active Assistants or Agents */ // /** meanwhile active Assistants or Agents */
activeTopicOrSession: 'topic' | 'session' // activeTopicOrSession: 'topic' | 'session'
/** topic ids that are currently being renamed */ // /** topic ids that are currently being renamed */
renamingTopics: string[] // renamingTopics: string[]
/** topic ids that are newly renamed */ // /** topic ids that are newly renamed */
newlyRenamedTopics: string[] // newlyRenamedTopics: string[]
/** is a session waiting for updating/deleting. undefined and false share same semantics. */ // /** is a session waiting for updating/deleting. undefined and false share same semantics. */
sessionWaiting: Record<string, boolean> // sessionWaiting: Record<string, boolean>
} // }
export interface WebSearchState { // export interface WebSearchState {
activeSearches: Record<string, WebSearchStatus> // activeSearches: Record<string, WebSearchStatus>
} // }
export interface UpdateState { // export interface UpdateState {
info: UpdateInfo | null // info: UpdateInfo | null
checking: boolean // checking: boolean
downloading: boolean // downloading: boolean
downloaded: boolean // downloaded: boolean
downloadProgress: number // downloadProgress: number
available: boolean // available: boolean
ignore: boolean // ignore: boolean
} // }
export interface RuntimeState { export interface RuntimeState {
// avatar: string // avatar: string
@ -59,13 +57,14 @@ export interface RuntimeState {
// resourcesPath: string // resourcesPath: string
// update: UpdateState // update: UpdateState
// export: ExportState // export: ExportState
chat: ChatState // chat: ChatState
// websearch: WebSearchState // websearch: WebSearchState
placeHolder: string
} }
export interface ExportState { // export interface ExportState {
isExporting: boolean // isExporting: boolean
} // }
const initialState: RuntimeState = { const initialState: RuntimeState = {
// avatar: UserAvatar, // avatar: UserAvatar,
@ -90,20 +89,21 @@ const initialState: RuntimeState = {
// export: { // export: {
// isExporting: false // isExporting: false
// }, // },
chat: { // chat: {
isMultiSelectMode: false, // isMultiSelectMode: false,
selectedMessageIds: [], // selectedMessageIds: [],
activeTopic: null, // activeTopic: null,
activeAgentId: null, // activeAgentId: null,
activeTopicOrSession: 'topic', // activeTopicOrSession: 'topic',
activeSessionIdMap: {}, // activeSessionIdMap: {},
renamingTopics: [], // renamingTopics: [],
newlyRenamedTopics: [], // newlyRenamedTopics: [],
sessionWaiting: {} // sessionWaiting: {}
} // }
// websearch: { // websearch: {
// activeSearches: {} // activeSearches: {}
// }, // },
placeHolder: ''
} }
const runtimeSlice = createSlice({ const runtimeSlice = createSlice({
@ -163,16 +163,16 @@ const runtimeSlice = createSlice({
// @ts-ignore ts2589 false positive // @ts-ignore ts2589 false positive
// state.chat.activeTopic = action.payload // state.chat.activeTopic = action.payload
// }, // },
setActiveAgentId: (state, action: PayloadAction<string | null>) => { // setActiveAgentId: (state, action: PayloadAction<string | null>) => {
state.chat.activeAgentId = action.payload // state.chat.activeAgentId = action.payload
}, // },
setActiveSessionIdAction: (state, action: PayloadAction<{ agentId: string; sessionId: string | null }>) => { // setActiveSessionIdAction: (state, action: PayloadAction<{ agentId: string; sessionId: string | null }>) => {
const { agentId, sessionId } = action.payload // const { agentId, sessionId } = action.payload
state.chat.activeSessionIdMap[agentId] = sessionId // state.chat.activeSessionIdMap[agentId] = sessionId
}, // },
setActiveTopicOrSessionAction: (state, action: PayloadAction<'topic' | 'session'>) => { // setActiveTopicOrSessionAction: (state, action: PayloadAction<'topic' | 'session'>) => {
state.chat.activeTopicOrSession = action.payload // state.chat.activeTopicOrSession = action.payload
}, // },
// setRenamingTopics: (state, action: PayloadAction<string[]>) => { // setRenamingTopics: (state, action: PayloadAction<string[]>) => {
// state.chat.renamingTopics = action.payload // state.chat.renamingTopics = action.payload
// }, // },
@ -191,9 +191,12 @@ const runtimeSlice = createSlice({
// state.websearch.activeSearches[requestId] = status // state.websearch.activeSearches[requestId] = status
// }, // },
// setPlaceholder: (state, action: PayloadAction<Partial<RuntimeState>>) => {}, // setPlaceholder: (state, action: PayloadAction<Partial<RuntimeState>>) => {},
setSessionWaitingAction: (state, action: PayloadAction<{ id: string; value: boolean }>) => { // setSessionWaitingAction: (state, action: PayloadAction<{ id: string; value: boolean }>) => {
const { id, value } = action.payload // const { id, value } = action.payload
state.chat.sessionWaiting[id] = value // state.chat.sessionWaiting[id] = value
// }
setPlaceholder: (state, action: PayloadAction<string>) => {
state.placeHolder = action.payload
} }
} }
}) })
@ -216,16 +219,16 @@ export const {
// toggleMultiSelectMode, // toggleMultiSelectMode,
// setSelectedMessageIds, // setSelectedMessageIds,
// setActiveTopic, // setActiveTopic,
setActiveAgentId, // setActiveAgentId,
setActiveSessionIdAction, // setActiveSessionIdAction,
setActiveTopicOrSessionAction, // setActiveTopicOrSessionAction,
// setRenamingTopics, // setRenamingTopics,
// setNewlyRenamedTopics, // setNewlyRenamedTopics,
setSessionWaitingAction // setSessionWaitingAction
// // WebSearch related actions // // WebSearch related actions
// setActiveSearches, // setActiveSearches,
// setWebSearchStatus, // setWebSearchStatus,
// setPlaceholder setPlaceholder
} = runtimeSlice.actions } = runtimeSlice.actions
export default runtimeSlice.reducer export default runtimeSlice.reducer