mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-04 20:00:00 +08:00
Merge branch 'v2' into feat/router-design
This commit is contained in:
commit
ec3c9db9ff
14
packages/shared/data/cache/cacheSchemas.ts
vendored
14
packages/shared/data/cache/cacheSchemas.ts
vendored
@ -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': {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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]
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -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(
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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)
|
|
||||||
}
|
|
||||||
@ -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)
|
||||||
|
|||||||
@ -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(() => {
|
||||||
|
|||||||
@ -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(
|
||||||
() =>
|
() =>
|
||||||
|
|||||||
@ -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()
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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()
|
||||||
|
|
||||||
|
|||||||
@ -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} />
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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(
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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]
|
||||||
|
|||||||
@ -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)'
|
||||||
|
|
||||||
|
|||||||
@ -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 () => {
|
||||||
|
|||||||
@ -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 }
|
||||||
|
|||||||
@ -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(() => {
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user