mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-08 14:29:15 +08:00
fix(chat): handle agent and session state changes properly
update activeAgentId type to allow null and reset state when deleting agent add validation for missing agent/session in UI components
This commit is contained in:
parent
c52cc5a94f
commit
0be2177937
@ -1,9 +1,12 @@
|
|||||||
|
import { useAppDispatch } from '@renderer/store'
|
||||||
|
import { setActiveAgentId, setActiveSessionIdAction } from '@renderer/store/runtime'
|
||||||
import { AddAgentForm } from '@renderer/types'
|
import { AddAgentForm } from '@renderer/types'
|
||||||
import { formatErrorMessageWithPrefix } from '@renderer/utils/error'
|
import { formatErrorMessageWithPrefix } from '@renderer/utils/error'
|
||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import useSWR from 'swr'
|
import useSWR from 'swr'
|
||||||
|
|
||||||
|
import { useRuntime } from '../useRuntime'
|
||||||
import { useAgentClient } from './useAgentClient'
|
import { useAgentClient } from './useAgentClient'
|
||||||
|
|
||||||
export const useAgents = () => {
|
export const useAgents = () => {
|
||||||
@ -16,6 +19,9 @@ export const useAgents = () => {
|
|||||||
return result.data
|
return result.data
|
||||||
}, [client])
|
}, [client])
|
||||||
const { data, error, isLoading, mutate } = useSWR(key, fetcher)
|
const { data, error, isLoading, mutate } = useSWR(key, fetcher)
|
||||||
|
const { chat } = useRuntime()
|
||||||
|
const { activeAgentId } = chat
|
||||||
|
const dispatch = useAppDispatch()
|
||||||
|
|
||||||
const addAgent = useCallback(
|
const addAgent = useCallback(
|
||||||
async (form: AddAgentForm) => {
|
async (form: AddAgentForm) => {
|
||||||
@ -34,6 +40,15 @@ 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 }))
|
||||||
|
if (activeAgentId === id) {
|
||||||
|
const newId = data?.filter((a) => a.id !== id).find(() => true)?.id
|
||||||
|
if (newId) {
|
||||||
|
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'))
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@ -18,7 +18,7 @@ import { classNames } from '@renderer/utils'
|
|||||||
import { Flex } from 'antd'
|
import { Flex } from 'antd'
|
||||||
import { debounce } from 'lodash'
|
import { debounce } from 'lodash'
|
||||||
import { AnimatePresence, motion } from 'motion/react'
|
import { AnimatePresence, motion } from 'motion/react'
|
||||||
import React, { FC, useMemo, useState } from 'react'
|
import React, { FC, useCallback, useMemo, useState } from 'react'
|
||||||
import { useHotkeys } from 'react-hotkeys-hook'
|
import { useHotkeys } from 'react-hotkeys-hook'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
@ -172,6 +172,27 @@ const Chat: FC<Props> = (props) => {
|
|||||||
return () => <AgentSessionInputbar agentId={activeAgentId} sessionId={sessionId} />
|
return () => <AgentSessionInputbar agentId={activeAgentId} sessionId={sessionId} />
|
||||||
}, [activeAgentId, activeSessionId])
|
}, [activeAgentId, activeSessionId])
|
||||||
|
|
||||||
|
// TODO: more info
|
||||||
|
const AgentInvalid = useCallback(() => {
|
||||||
|
return (
|
||||||
|
<div className="flex h-full w-full items-center justify-center">
|
||||||
|
<div>
|
||||||
|
<Alert color="warning" title="Select an agent" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
// TODO: more info
|
||||||
|
const SessionInvalid = useCallback(() => {
|
||||||
|
return (
|
||||||
|
<div className="flex h-full w-full items-center justify-center">
|
||||||
|
<div>
|
||||||
|
<Alert color="warning" title="Create a session" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}, [])
|
||||||
return (
|
return (
|
||||||
<Container id="chat" className={classNames([messageStyle, { 'multi-select-mode': isMultiSelectMode }])}>
|
<Container id="chat" className={classNames([messageStyle, { 'multi-select-mode': isMultiSelectMode }])}>
|
||||||
{isTopNavbar && (
|
{isTopNavbar && (
|
||||||
@ -213,7 +234,11 @@ const Chat: FC<Props> = (props) => {
|
|||||||
<Inputbar assistant={assistant} setActiveTopic={props.setActiveTopic} topic={props.activeTopic} />
|
<Inputbar assistant={assistant} setActiveTopic={props.setActiveTopic} topic={props.activeTopic} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{activeTopicOrSession === 'session' && (
|
{activeTopicOrSession === 'session' && !activeAgentId && <AgentInvalid />}
|
||||||
|
{activeTopicOrSession === 'session' && activeAgentId && !activeSessionId[activeAgentId] && (
|
||||||
|
<SessionInvalid />
|
||||||
|
)}
|
||||||
|
{activeTopicOrSession === 'session' && activeAgentId && activeSessionId[activeAgentId] && (
|
||||||
<>
|
<>
|
||||||
<SessionMessages />
|
<SessionMessages />
|
||||||
<SessionInputBar />
|
<SessionInputBar />
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Alert, cn, Spinner } from '@heroui/react'
|
import { Alert, cn } from '@heroui/react'
|
||||||
import { useRuntime } from '@renderer/hooks/useRuntime'
|
import { useRuntime } from '@renderer/hooks/useRuntime'
|
||||||
import { useSettings } from '@renderer/hooks/useSettings'
|
import { useSettings } from '@renderer/hooks/useSettings'
|
||||||
import { AnimatePresence, motion } from 'framer-motion'
|
import { AnimatePresence, motion } from 'framer-motion'
|
||||||
@ -24,6 +24,14 @@ const SessionsTab: FC<SessionsTabProps> = () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!activeAgentId) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Alert color="warning" title={'Select an agent'} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AnimatePresence mode="wait">
|
<AnimatePresence mode="wait">
|
||||||
<motion.div
|
<motion.div
|
||||||
@ -35,26 +43,7 @@ const SessionsTab: FC<SessionsTabProps> = () => {
|
|||||||
'overflow-hidden',
|
'overflow-hidden',
|
||||||
topicPosition === 'right' && navbarPosition === 'top' ? 'rounded-l-2xl border-t border-b border-l' : undefined
|
topicPosition === 'right' && navbarPosition === 'top' ? 'rounded-l-2xl border-t border-b border-l' : undefined
|
||||||
)}>
|
)}>
|
||||||
{!activeAgentId ? (
|
<Sessions agentId={activeAgentId} />
|
||||||
<motion.div
|
|
||||||
key="loading"
|
|
||||||
initial={{ opacity: 0 }}
|
|
||||||
animate={{ opacity: 1 }}
|
|
||||||
exit={{ opacity: 0 }}
|
|
||||||
transition={{ duration: 0.3 }}
|
|
||||||
className="flex h-full flex-col items-center justify-center gap-3">
|
|
||||||
<Spinner size="lg" color="primary" />
|
|
||||||
<motion.p
|
|
||||||
initial={{ opacity: 0, y: 5 }}
|
|
||||||
animate={{ opacity: 1, y: 0 }}
|
|
||||||
transition={{ delay: 0.2, duration: 0.3 }}
|
|
||||||
className="text-foreground-500 text-sm">
|
|
||||||
{t('common.loading')}...
|
|
||||||
</motion.p>
|
|
||||||
</motion.div>
|
|
||||||
) : (
|
|
||||||
<Sessions agentId={activeAgentId} />
|
|
||||||
)}
|
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -158,7 +158,7 @@ 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>) => {
|
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 }>) => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user