feat: agent rename to assistant
This commit is contained in:
parent
6408762f40
commit
900052e581
@ -34,9 +34,9 @@
|
||||
|
||||
--navbar-height: 42px;
|
||||
--sidebar-width: 68px;
|
||||
--agents-width: 250px;
|
||||
--topic-list-width: var(--agents-width);
|
||||
--settings-width: var(--agents-width);
|
||||
--assistants-width: 250px;
|
||||
--topic-list-width: var(--assistants-width);
|
||||
--settings-width: var(--assistants-width);
|
||||
--status-bar-height: 40px;
|
||||
--input-bar-height: 120px;
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
font-size: 15px;
|
||||
line-height: 1.6;
|
||||
user-select: text;
|
||||
margin-top: 4px;
|
||||
|
||||
.hljs {
|
||||
background-color: transparent;
|
||||
|
||||
@ -2,21 +2,21 @@ import { Input, Modal } from 'antd'
|
||||
import { useState } from 'react'
|
||||
import { TopView } from '../TopView'
|
||||
import { Box } from '../Layout'
|
||||
import { Agent } from '@renderer/types'
|
||||
import { Assistant } from '@renderer/types'
|
||||
import TextArea from 'antd/es/input/TextArea'
|
||||
|
||||
interface AgentSettingPopupShowParams {
|
||||
agent: Agent
|
||||
interface AssistantSettingPopupShowParams {
|
||||
assistant: Assistant
|
||||
}
|
||||
|
||||
interface Props extends AgentSettingPopupShowParams {
|
||||
resolve: (agent: Agent) => void
|
||||
interface Props extends AssistantSettingPopupShowParams {
|
||||
resolve: (assistant: Assistant) => void
|
||||
}
|
||||
|
||||
const AgentSettingPopupContainer: React.FC<Props> = ({ agent, resolve }) => {
|
||||
const [name, setName] = useState(agent.name)
|
||||
const [description, setDescription] = useState(agent.description)
|
||||
const [prompt, setPrompt] = useState(agent.prompt)
|
||||
const AssistantSettingPopupContainer: React.FC<Props> = ({ assistant, resolve }) => {
|
||||
const [name, setName] = useState(assistant.name)
|
||||
const [description, setDescription] = useState(assistant.description)
|
||||
const [prompt, setPrompt] = useState(assistant.prompt)
|
||||
const [open, setOpen] = useState(true)
|
||||
|
||||
const onOk = () => {
|
||||
@ -28,19 +28,19 @@ const AgentSettingPopupContainer: React.FC<Props> = ({ agent, resolve }) => {
|
||||
}
|
||||
|
||||
const onClose = () => {
|
||||
resolve({ ...agent, name, description, prompt })
|
||||
resolve({ ...assistant, name, description, prompt })
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal title={agent.name} open={open} onOk={onOk} onCancel={handleCancel} afterClose={onClose}>
|
||||
<Modal title={assistant.name} open={open} onOk={onOk} onCancel={handleCancel} afterClose={onClose}>
|
||||
<Box mb={8}>Name</Box>
|
||||
<Input placeholder="Agent Name" value={name} onChange={(e) => setName(e.target.value)} autoFocus />
|
||||
<Input placeholder="Assistant Name" value={name} onChange={(e) => setName(e.target.value)} autoFocus />
|
||||
<Box mt={8} mb={8}>
|
||||
Description
|
||||
</Box>
|
||||
<TextArea
|
||||
rows={4}
|
||||
placeholder="Agent Description"
|
||||
placeholder="Assistant Description"
|
||||
value={description}
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
autoFocus
|
||||
@ -50,7 +50,7 @@ const AgentSettingPopupContainer: React.FC<Props> = ({ agent, resolve }) => {
|
||||
</Box>
|
||||
<TextArea
|
||||
rows={4}
|
||||
placeholder="Agent Prompt"
|
||||
placeholder="Assistant Prompt"
|
||||
value={prompt}
|
||||
onChange={(e) => setPrompt(e.target.value)}
|
||||
autoFocus
|
||||
@ -59,15 +59,15 @@ const AgentSettingPopupContainer: React.FC<Props> = ({ agent, resolve }) => {
|
||||
)
|
||||
}
|
||||
|
||||
export default class AgentSettingPopup {
|
||||
export default class AssistantSettingPopup {
|
||||
static topviewId = 0
|
||||
static hide() {
|
||||
TopView.hide(this.topviewId)
|
||||
}
|
||||
static show(props: AgentSettingPopupShowParams) {
|
||||
return new Promise<Agent>((resolve) => {
|
||||
static show(props: AssistantSettingPopupShowParams) {
|
||||
return new Promise<Assistant>((resolve) => {
|
||||
this.topviewId = TopView.show(
|
||||
<AgentSettingPopupContainer
|
||||
<AssistantSettingPopupContainer
|
||||
{...props}
|
||||
resolve={(v) => {
|
||||
resolve(v)
|
||||
@ -31,7 +31,7 @@ const NavbarContainer = styled.div`
|
||||
`
|
||||
|
||||
const NavbarLeftContainer = styled.div`
|
||||
min-width: var(--agents-width);
|
||||
min-width: var(--assistants-width);
|
||||
border-right: 1px solid var(--color-border);
|
||||
padding: 0 16px;
|
||||
display: flex;
|
||||
|
||||
@ -24,7 +24,7 @@ const Container = styled.div`
|
||||
`
|
||||
|
||||
const StatusbarLeft = styled.div`
|
||||
min-width: var(--sidebar-width) + var(--agents-width);
|
||||
min-width: var(--sidebar-width) + var(--assistants-width);
|
||||
`
|
||||
|
||||
const StatusbarCenter = styled.div`
|
||||
|
||||
@ -1,51 +0,0 @@
|
||||
import { useAppDispatch, useAppSelector } from '@renderer/store'
|
||||
import {
|
||||
addTopic as _addTopic,
|
||||
removeAllTopics as _removeAllTopics,
|
||||
removeTopic as _removeTopic,
|
||||
updateTopic as _updateTopic,
|
||||
addAgent,
|
||||
removeAgent,
|
||||
updateAgent
|
||||
} from '@renderer/store/agents'
|
||||
import { Agent, Topic } from '@renderer/types'
|
||||
import localforage from 'localforage'
|
||||
|
||||
export default function useAgents() {
|
||||
const { agents } = useAppSelector((state) => state.agents)
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
return {
|
||||
agents,
|
||||
addAgent: (agent: Agent) => dispatch(addAgent(agent)),
|
||||
removeAgent: (id: string) => {
|
||||
dispatch(removeAgent({ id }))
|
||||
const agent = agents.find((a) => a.id === id)
|
||||
if (agent) {
|
||||
agent.topics.forEach((id) => localforage.removeItem(`topic:${id}`))
|
||||
}
|
||||
},
|
||||
updateAgent: (agent: Agent) => dispatch(updateAgent(agent))
|
||||
}
|
||||
}
|
||||
|
||||
export function useAgent(id: string) {
|
||||
const agent = useAppSelector((state) => state.agents.agents.find((a) => a.id === id) as Agent)
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
return {
|
||||
agent,
|
||||
addTopic: (topic: Topic) => {
|
||||
dispatch(_addTopic({ agentId: agent.id, topic }))
|
||||
},
|
||||
removeTopic: (topic: Topic) => {
|
||||
dispatch(_removeTopic({ agentId: agent.id, topic }))
|
||||
},
|
||||
updateTopic: (topic: Topic) => {
|
||||
dispatch(_updateTopic({ agentId: agent.id, topic }))
|
||||
},
|
||||
removeAllTopics: () => {
|
||||
dispatch(_removeAllTopics({ agentId: agent.id }))
|
||||
}
|
||||
}
|
||||
}
|
||||
51
src/renderer/src/hooks/useAssistants.ts
Normal file
51
src/renderer/src/hooks/useAssistants.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import { useAppDispatch, useAppSelector } from '@renderer/store'
|
||||
import {
|
||||
addTopic as _addTopic,
|
||||
removeAllTopics as _removeAllTopics,
|
||||
removeTopic as _removeTopic,
|
||||
updateTopic as _updateTopic,
|
||||
addAssistant,
|
||||
removeAssistant,
|
||||
updateAssistant
|
||||
} from '@renderer/store/assistants'
|
||||
import { Assistant, Topic } from '@renderer/types'
|
||||
import localforage from 'localforage'
|
||||
|
||||
export default function useAssistants() {
|
||||
const { assistants } = useAppSelector((state) => state.assistants)
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
return {
|
||||
assistants,
|
||||
addAssistant: (assistant: Assistant) => dispatch(addAssistant(assistant)),
|
||||
removeAssistant: (id: string) => {
|
||||
dispatch(removeAssistant({ id }))
|
||||
const assistant = assistants.find((a) => a.id === id)
|
||||
if (assistant) {
|
||||
assistant.topics.forEach((id) => localforage.removeItem(`topic:${id}`))
|
||||
}
|
||||
},
|
||||
updateAssistant: (assistant: Assistant) => dispatch(updateAssistant(assistant))
|
||||
}
|
||||
}
|
||||
|
||||
export function useAssistant(id: string) {
|
||||
const assistant = useAppSelector((state) => state.assistants.assistants.find((a) => a.id === id) as Assistant)
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
return {
|
||||
assistant,
|
||||
addTopic: (topic: Topic) => {
|
||||
dispatch(_addTopic({ assistantId: assistant.id, topic }))
|
||||
},
|
||||
removeTopic: (topic: Topic) => {
|
||||
dispatch(_removeTopic({ assistantId: assistant.id, topic }))
|
||||
},
|
||||
updateTopic: (topic: Topic) => {
|
||||
dispatch(_updateTopic({ assistantId: assistant.id, topic }))
|
||||
},
|
||||
removeAllTopics: () => {
|
||||
dispatch(_removeAllTopics({ assistantId: assistant.id }))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,12 +1,12 @@
|
||||
import { Agent } from '@renderer/types'
|
||||
import { Assistant } from '@renderer/types'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
export function useActiveTopic(agent: Agent) {
|
||||
const [activeTopic, setActiveTopic] = useState(agent?.topics[0])
|
||||
export function useActiveTopic(assistant: Assistant) {
|
||||
const [activeTopic, setActiveTopic] = useState(assistant?.topics[0])
|
||||
|
||||
useEffect(() => {
|
||||
agent?.topics && setActiveTopic(agent?.topics[0])
|
||||
}, [agent])
|
||||
assistant?.topics && setActiveTopic(assistant?.topics[0])
|
||||
}, [assistant])
|
||||
|
||||
return { activeTopic, setActiveTopic }
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ const AppsPage: FC = () => {
|
||||
return (
|
||||
<Container>
|
||||
<Navbar>
|
||||
<NavbarCenter>Agent Market</NavbarCenter>
|
||||
<NavbarCenter>Assistant Market</NavbarCenter>
|
||||
</Navbar>
|
||||
</Container>
|
||||
)
|
||||
|
||||
@ -1,35 +1,35 @@
|
||||
import { Navbar, NavbarCenter, NavbarLeft, NavbarRight } from '@renderer/components/app/Navbar'
|
||||
import useAgents from '@renderer/hooks/useAgents'
|
||||
import useAssistants from '@renderer/hooks/useAssistants'
|
||||
import { FC, useState } from 'react'
|
||||
import styled from 'styled-components'
|
||||
import Chat from './components/Chat/Chat'
|
||||
import Agents from './components/Agents'
|
||||
import Assistants from './components/Assistants'
|
||||
import { uuid } from '@renderer/utils'
|
||||
import { getDefaultAgent } from '@renderer/services/agent'
|
||||
import { getDefaultAssistant } from '@renderer/services/assistant'
|
||||
import { useShowRightSidebar } from '@renderer/hooks/useStore'
|
||||
import { Tooltip } from 'antd'
|
||||
|
||||
const HomePage: FC = () => {
|
||||
const { agents, addAgent } = useAgents()
|
||||
const [activeAgent, setActiveAgent] = useState(agents[0])
|
||||
const { assistants, addAssistant } = useAssistants()
|
||||
const [activeAssistant, setActiveAssistant] = useState(assistants[0])
|
||||
const { showRightSidebar, setShowRightSidebar } = useShowRightSidebar()
|
||||
|
||||
const onCreateAgent = () => {
|
||||
const _agent = getDefaultAgent()
|
||||
_agent.id = uuid()
|
||||
addAgent(_agent)
|
||||
setActiveAgent(_agent)
|
||||
const onCreateAssistant = () => {
|
||||
const _assistant = getDefaultAssistant()
|
||||
_assistant.id = uuid()
|
||||
addAssistant(_assistant)
|
||||
setActiveAssistant(_assistant)
|
||||
}
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Navbar>
|
||||
<NavbarLeft style={{ justifyContent: 'flex-end', borderRight: 'none' }}>
|
||||
<NewButton onClick={onCreateAgent}>
|
||||
<NewButton onClick={onCreateAssistant}>
|
||||
<i className="iconfont icon-a-addchat"></i>
|
||||
</NewButton>
|
||||
</NavbarLeft>
|
||||
<NavbarCenter style={{ border: 'none' }}>{activeAgent?.name}</NavbarCenter>
|
||||
<NavbarCenter style={{ border: 'none' }}>{activeAssistant?.name}</NavbarCenter>
|
||||
<NavbarRight style={{ justifyContent: 'flex-end', padding: 5 }}>
|
||||
<Tooltip placement="left" title={showRightSidebar ? 'Hide Topics' : 'Show Topics'} arrow>
|
||||
<NewButton onClick={setShowRightSidebar}>
|
||||
@ -39,8 +39,8 @@ const HomePage: FC = () => {
|
||||
</NavbarRight>
|
||||
</Navbar>
|
||||
<ContentContainer>
|
||||
<Agents activeAgent={activeAgent} onActive={setActiveAgent} />
|
||||
<Chat agent={activeAgent} />
|
||||
<Assistants activeAssistant={activeAssistant} onActive={setActiveAssistant} />
|
||||
<Chat assistant={activeAssistant} />
|
||||
</ContentContainer>
|
||||
</Container>
|
||||
)
|
||||
|
||||
@ -1,147 +0,0 @@
|
||||
import { FC, useRef } from 'react'
|
||||
import styled from 'styled-components'
|
||||
import useAgents from '@renderer/hooks/useAgents'
|
||||
import { Agent } from '@renderer/types'
|
||||
import { Dropdown, MenuProps } from 'antd'
|
||||
import { MoreOutlined } from '@ant-design/icons'
|
||||
import { last } from 'lodash'
|
||||
import AgentSettingPopup from '@renderer/components/Popups/AgentSettingPopup'
|
||||
import { DeleteOutlined, EditOutlined } from '@ant-design/icons'
|
||||
|
||||
interface Props {
|
||||
activeAgent: Agent
|
||||
onActive: (agent: Agent) => void
|
||||
}
|
||||
|
||||
const Agents: FC<Props> = ({ activeAgent, onActive }) => {
|
||||
const { agents, removeAgent, updateAgent } = useAgents()
|
||||
const targetAgent = useRef<Agent | null>(null)
|
||||
|
||||
const onDelete = (agent: Agent) => {
|
||||
removeAgent(agent.id)
|
||||
setTimeout(() => {
|
||||
const _agent = last(agents.filter((a) => a.id !== agent.id))
|
||||
_agent && onActive(_agent)
|
||||
}, 0)
|
||||
}
|
||||
|
||||
const items: MenuProps['items'] = [
|
||||
{
|
||||
label: 'Edit',
|
||||
key: 'edit',
|
||||
icon: <EditOutlined />,
|
||||
async onClick() {
|
||||
if (targetAgent.current) {
|
||||
const _agent = await AgentSettingPopup.show({ agent: targetAgent.current })
|
||||
updateAgent(_agent)
|
||||
}
|
||||
}
|
||||
},
|
||||
{ type: 'divider' },
|
||||
{
|
||||
label: 'Delete',
|
||||
key: 'delete',
|
||||
icon: <DeleteOutlined />,
|
||||
danger: true,
|
||||
onClick: () => targetAgent.current && onDelete(targetAgent.current)
|
||||
}
|
||||
]
|
||||
|
||||
return (
|
||||
<Container>
|
||||
{agents.map((agent) => (
|
||||
<AgentItem
|
||||
data-id={agent.id}
|
||||
key={agent.id}
|
||||
onClick={() => onActive(agent)}
|
||||
className={agent.id === activeAgent?.id ? 'active' : ''}>
|
||||
<Dropdown
|
||||
menu={{ items }}
|
||||
trigger={['click']}
|
||||
placement="bottom"
|
||||
arrow
|
||||
onOpenChange={() => (targetAgent.current = agent)}>
|
||||
<MenuButton className="menu-button" onClick={(e) => e.stopPropagation()}>
|
||||
<MoreOutlined />
|
||||
</MenuButton>
|
||||
</Dropdown>
|
||||
<AgentName>{agent.name}</AgentName>
|
||||
<AgentLastMessage>{agent.description}</AgentLastMessage>
|
||||
</AgentItem>
|
||||
))}
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: var(--agents-width);
|
||||
max-width: var(--agents-width);
|
||||
border-right: 0.5px solid var(--color-border);
|
||||
height: calc(100vh - var(--navbar-height));
|
||||
overflow-y: scroll;
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
`
|
||||
|
||||
const AgentItem = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 10px 15px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
.anticon {
|
||||
display: none;
|
||||
}
|
||||
&:hover {
|
||||
background-color: var(--color-background-soft);
|
||||
.anticon {
|
||||
display: block;
|
||||
color: var(--color-text-1);
|
||||
}
|
||||
}
|
||||
&.active {
|
||||
background-color: var(--color-background-mute);
|
||||
cursor: pointer;
|
||||
}
|
||||
`
|
||||
|
||||
const AgentName = styled.div`
|
||||
font-size: 14px;
|
||||
color: var(--color-text-1);
|
||||
font-weight: bold;
|
||||
`
|
||||
|
||||
const AgentLastMessage = styled.div`
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
color: var(--color-text-2);
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-line-clamp: 1;
|
||||
height: 20px;
|
||||
`
|
||||
|
||||
const MenuButton = styled.div`
|
||||
padding: 5px;
|
||||
position: absolute;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
font-size: 18px;
|
||||
border-radius: 50%;
|
||||
transition: background-color 0.2s ease;
|
||||
&:hover {
|
||||
background-color: #ffffff30;
|
||||
.anticon {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export default Agents
|
||||
160
src/renderer/src/pages/home/components/Assistants.tsx
Normal file
160
src/renderer/src/pages/home/components/Assistants.tsx
Normal file
@ -0,0 +1,160 @@
|
||||
import { FC, useRef } from 'react'
|
||||
import styled from 'styled-components'
|
||||
import useAssistants from '@renderer/hooks/useAssistants'
|
||||
import { Assistant } from '@renderer/types'
|
||||
import { Button, Dropdown, MenuProps } from 'antd'
|
||||
import { MoreOutlined } from '@ant-design/icons'
|
||||
import { last } from 'lodash'
|
||||
import AssistantSettingPopup from '@renderer/components/Popups/AssistantSettingPopup'
|
||||
import { DeleteOutlined, EditOutlined } from '@ant-design/icons'
|
||||
|
||||
interface Props {
|
||||
activeAssistant: Assistant
|
||||
onActive: (assistant: Assistant) => void
|
||||
}
|
||||
|
||||
const Assistants: FC<Props> = ({ activeAssistant, onActive }) => {
|
||||
const { assistants, removeAssistant, updateAssistant } = useAssistants()
|
||||
const targetAssistant = useRef<Assistant | null>(null)
|
||||
const menuOpenRef = useRef(false)
|
||||
|
||||
const onDelete = (assistant: Assistant) => {
|
||||
removeAssistant(assistant.id)
|
||||
setTimeout(() => {
|
||||
const _assistant = last(assistants.filter((a) => a.id !== assistant.id))
|
||||
_assistant && onActive(_assistant)
|
||||
}, 0)
|
||||
}
|
||||
|
||||
const items: MenuProps['items'] = [
|
||||
{
|
||||
label: 'Edit',
|
||||
key: 'edit',
|
||||
icon: <EditOutlined />,
|
||||
async onClick() {
|
||||
if (targetAssistant.current) {
|
||||
const _assistant = await AssistantSettingPopup.show({ assistant: targetAssistant.current })
|
||||
updateAssistant(_assistant)
|
||||
}
|
||||
}
|
||||
},
|
||||
{ type: 'divider' },
|
||||
{
|
||||
label: 'Delete',
|
||||
key: 'delete',
|
||||
icon: <DeleteOutlined />,
|
||||
danger: true,
|
||||
onClick: () => {
|
||||
targetAssistant.current && onDelete(targetAssistant.current)
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
return (
|
||||
<Container>
|
||||
{assistants.map((assistant) => (
|
||||
<Dropdown
|
||||
key={assistant.id}
|
||||
menu={{ items }}
|
||||
trigger={['contextMenu']}
|
||||
onOpenChange={() => (targetAssistant.current = assistant)}>
|
||||
<AssistantItem
|
||||
onClick={() => onActive(assistant)}
|
||||
className={assistant.id === activeAssistant?.id ? 'active' : ''}>
|
||||
<Dropdown
|
||||
menu={{ items }}
|
||||
trigger={['click']}
|
||||
placement="bottom"
|
||||
destroyPopupOnHide
|
||||
arrow
|
||||
onOpenChange={() => (targetAssistant.current = assistant)}>
|
||||
<MenuButton type="text" onClick={(e) => e.stopPropagation()}>
|
||||
<MoreOutlined />
|
||||
</MenuButton>
|
||||
</Dropdown>
|
||||
<AssistantName>{assistant.name}</AssistantName>
|
||||
<AssistantLastMessage>{assistant.description}</AssistantLastMessage>
|
||||
</AssistantItem>
|
||||
</Dropdown>
|
||||
))}
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: var(--assistants-width);
|
||||
max-width: var(--assistants-width);
|
||||
border-right: 0.5px solid var(--color-border);
|
||||
height: calc(100vh - var(--navbar-height));
|
||||
overflow-y: scroll;
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
`
|
||||
|
||||
const AssistantItem = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 10px 15px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
.anticon {
|
||||
display: none;
|
||||
}
|
||||
&:hover {
|
||||
background-color: var(--color-background-soft);
|
||||
.anticon {
|
||||
display: block;
|
||||
color: var(--color-text-1);
|
||||
}
|
||||
}
|
||||
&.active {
|
||||
background-color: var(--color-background-mute);
|
||||
cursor: pointer;
|
||||
}
|
||||
`
|
||||
|
||||
const AssistantName = styled.div`
|
||||
font-size: 14px;
|
||||
color: var(--color-text-1);
|
||||
font-weight: bold;
|
||||
`
|
||||
|
||||
const AssistantLastMessage = styled.div`
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
color: var(--color-text-2);
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-line-clamp: 1;
|
||||
height: 20px;
|
||||
`
|
||||
|
||||
const MenuButton = styled(Button)`
|
||||
position: absolute;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
padding: 0;
|
||||
right: 6px;
|
||||
top: 6px;
|
||||
font-size: 18px;
|
||||
border-radius: 50%;
|
||||
transition: background-color 0.2s ease;
|
||||
z-index: 10;
|
||||
.anticon {
|
||||
transition: all 0.3s ease;
|
||||
color: var(--color-icon);
|
||||
}
|
||||
&:hover {
|
||||
background-color: #ffffff30;
|
||||
.anticon {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export default Assistants
|
||||
@ -1,32 +1,32 @@
|
||||
import { Agent } from '@renderer/types'
|
||||
import { Assistant } from '@renderer/types'
|
||||
import { FC } from 'react'
|
||||
import styled from 'styled-components'
|
||||
import Inputbar from './Inputbar'
|
||||
import Conversations from './Conversations'
|
||||
import { Flex } from 'antd'
|
||||
import TopicList from './TopicList'
|
||||
import { useAgent } from '@renderer/hooks/useAgents'
|
||||
import { useAssistant } from '@renderer/hooks/useAssistants'
|
||||
import { useActiveTopic } from '@renderer/hooks/useTopic'
|
||||
|
||||
interface Props {
|
||||
agent: Agent
|
||||
assistant: Assistant
|
||||
}
|
||||
|
||||
const Chat: FC<Props> = (props) => {
|
||||
const { agent } = useAgent(props.agent.id)
|
||||
const { activeTopic, setActiveTopic } = useActiveTopic(agent)
|
||||
const { assistant } = useAssistant(props.assistant.id)
|
||||
const { activeTopic, setActiveTopic } = useActiveTopic(assistant)
|
||||
|
||||
if (!agent) {
|
||||
if (!assistant) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Container id="chat">
|
||||
<Flex vertical flex={1} justify="space-between">
|
||||
<Conversations agent={agent} topic={activeTopic} />
|
||||
<Inputbar agent={agent} setActiveTopic={setActiveTopic} />
|
||||
<Conversations assistant={assistant} topic={activeTopic} />
|
||||
<Inputbar assistant={assistant} setActiveTopic={setActiveTopic} />
|
||||
</Flex>
|
||||
<TopicList agent={agent} activeTopic={activeTopic} setActiveTopic={setActiveTopic} />
|
||||
<TopicList assistant={assistant} activeTopic={activeTopic} setActiveTopic={setActiveTopic} />
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { EVENT_NAMES, EventEmitter } from '@renderer/services/event'
|
||||
import { Agent, Message, Topic } from '@renderer/types'
|
||||
import { Assistant, Message, Topic } from '@renderer/types'
|
||||
import localforage from 'localforage'
|
||||
import { FC, useCallback, useEffect, useState } from 'react'
|
||||
import styled from 'styled-components'
|
||||
@ -7,20 +7,20 @@ import MessageItem from './Message'
|
||||
import { reverse } from 'lodash'
|
||||
import hljs from 'highlight.js'
|
||||
import { fetchChatCompletion, fetchConversationSummary } from '@renderer/services/api'
|
||||
import { useAgent } from '@renderer/hooks/useAgents'
|
||||
import { useAssistant } from '@renderer/hooks/useAssistants'
|
||||
import { DEFAULT_TOPIC_NAME } from '@renderer/config/constant'
|
||||
import { runAsyncFunction } from '@renderer/utils'
|
||||
import LocalStorage from '@renderer/services/storage'
|
||||
|
||||
interface Props {
|
||||
agent: Agent
|
||||
assistant: Assistant
|
||||
topic: Topic
|
||||
}
|
||||
|
||||
const Conversations: FC<Props> = ({ agent, topic }) => {
|
||||
const Conversations: FC<Props> = ({ assistant, topic }) => {
|
||||
const [messages, setMessages] = useState<Message[]>([])
|
||||
const [lastMessage, setLastMessage] = useState<Message | null>(null)
|
||||
const { updateTopic } = useAgent(agent.id)
|
||||
const { updateTopic } = useAssistant(assistant.id)
|
||||
|
||||
const onSendMessage = useCallback(
|
||||
(message: Message) => {
|
||||
@ -47,7 +47,7 @@ const Conversations: FC<Props> = ({ agent, topic }) => {
|
||||
const unsubscribes = [
|
||||
EventEmitter.on(EVENT_NAMES.SEND_MESSAGE, async (msg: Message) => {
|
||||
onSendMessage(msg)
|
||||
fetchChatCompletion({ agent, message: msg, topic, onResponse: setLastMessage })
|
||||
fetchChatCompletion({ assistant, message: msg, topic, onResponse: setLastMessage })
|
||||
}),
|
||||
EventEmitter.on(EVENT_NAMES.AI_CHAT_COMPLETION, async (msg: Message) => {
|
||||
setLastMessage(null)
|
||||
@ -62,7 +62,7 @@ const Conversations: FC<Props> = ({ agent, topic }) => {
|
||||
})
|
||||
]
|
||||
return () => unsubscribes.forEach((unsub) => unsub())
|
||||
}, [agent, autoRenameTopic, onSendMessage, topic, updateTopic])
|
||||
}, [assistant, autoRenameTopic, onSendMessage, topic, updateTopic])
|
||||
|
||||
useEffect(() => {
|
||||
runAsyncFunction(async () => {
|
||||
|
||||
@ -1,33 +1,33 @@
|
||||
import { EVENT_NAMES, EventEmitter } from '@renderer/services/event'
|
||||
import { Agent, Message, Topic } from '@renderer/types'
|
||||
import { Assistant, Message, Topic } from '@renderer/types'
|
||||
import { uuid } from '@renderer/utils'
|
||||
import { FC, useState } from 'react'
|
||||
import styled from 'styled-components'
|
||||
import { MoreOutlined } from '@ant-design/icons'
|
||||
import { Button, Popconfirm, Tooltip } from 'antd'
|
||||
import { useShowRightSidebar } from '@renderer/hooks/useStore'
|
||||
import { useAgent } from '@renderer/hooks/useAgents'
|
||||
import { useAssistant } from '@renderer/hooks/useAssistants'
|
||||
import { ClearOutlined, HistoryOutlined, PlusCircleOutlined } from '@ant-design/icons'
|
||||
|
||||
interface Props {
|
||||
agent: Agent
|
||||
assistant: Assistant
|
||||
setActiveTopic: (topic: Topic) => void
|
||||
}
|
||||
|
||||
const Inputbar: FC<Props> = ({ agent, setActiveTopic }) => {
|
||||
const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
|
||||
const [text, setText] = useState('')
|
||||
const { setShowRightSidebar } = useShowRightSidebar()
|
||||
const { addTopic } = useAgent(agent.id)
|
||||
const { addTopic } = useAssistant(assistant.id)
|
||||
|
||||
const handleKeyDown = (event: React.KeyboardEvent<HTMLTextAreaElement>) => {
|
||||
if (event.key === 'Enter') {
|
||||
const topicId = agent.topics[0] ? agent.topics[0] : uuid()
|
||||
const topicId = assistant.topics[0] ? assistant.topics[0] : uuid()
|
||||
|
||||
const message: Message = {
|
||||
id: uuid(),
|
||||
role: 'user',
|
||||
content: text,
|
||||
agentId: agent.id,
|
||||
assistantId: assistant.id,
|
||||
topicId,
|
||||
createdAt: 'now'
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ const MessageItem: FC<{ message: Message }> = ({ message }) => {
|
||||
return (
|
||||
<MessageContainer key={message.id}>
|
||||
<AvatarWrapper>
|
||||
{message.role === 'agent' ? <Avatar src={Logo} /> : <Avatar alt="Alice Swift">Y</Avatar>}
|
||||
{message.role === 'assistant' ? <Avatar src={Logo} /> : <Avatar alt="Alice Swift">Y</Avatar>}
|
||||
</AvatarWrapper>
|
||||
<div className="markdown" dangerouslySetInnerHTML={{ __html: marked(message.content) }}></div>
|
||||
</MessageContainer>
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import PromptPopup from '@renderer/components/Popups/PromptPopup'
|
||||
import { useAgent } from '@renderer/hooks/useAgents'
|
||||
import { useAssistant } from '@renderer/hooks/useAssistants'
|
||||
import { useShowRightSidebar } from '@renderer/hooks/useStore'
|
||||
import { fetchConversationSummary } from '@renderer/services/api'
|
||||
import { Agent, Topic } from '@renderer/types'
|
||||
import { Assistant, Topic } from '@renderer/types'
|
||||
import { Button, Dropdown, MenuProps, Popconfirm } from 'antd'
|
||||
import { FC, useRef } from 'react'
|
||||
import styled from 'styled-components'
|
||||
@ -10,14 +10,14 @@ import { DeleteOutlined, EditOutlined, SignatureOutlined } from '@ant-design/ico
|
||||
import LocalStorage from '@renderer/services/storage'
|
||||
|
||||
interface Props {
|
||||
agent: Agent
|
||||
assistant: Assistant
|
||||
activeTopic: Topic
|
||||
setActiveTopic: (topic: Topic) => void
|
||||
}
|
||||
|
||||
const TopicList: FC<Props> = ({ agent, activeTopic, setActiveTopic }) => {
|
||||
const TopicList: FC<Props> = ({ assistant, activeTopic, setActiveTopic }) => {
|
||||
const { showRightSidebar } = useShowRightSidebar()
|
||||
const { removeTopic, updateTopic, removeAllTopics } = useAgent(agent.id)
|
||||
const { removeTopic, updateTopic, removeAllTopics } = useAssistant(assistant.id)
|
||||
const currentTopic = useRef<Topic | null>(null)
|
||||
|
||||
const topicMenuItems: MenuProps['items'] = [
|
||||
@ -54,7 +54,7 @@ const TopicList: FC<Props> = ({ agent, activeTopic, setActiveTopic }) => {
|
||||
}
|
||||
]
|
||||
|
||||
if (agent.topics.length > 1) {
|
||||
if (assistant.topics.length > 1) {
|
||||
topicMenuItems.push({ type: 'divider' })
|
||||
topicMenuItems.push({
|
||||
label: 'Delete',
|
||||
@ -62,10 +62,10 @@ const TopicList: FC<Props> = ({ agent, activeTopic, setActiveTopic }) => {
|
||||
key: 'delete',
|
||||
icon: <DeleteOutlined />,
|
||||
onClick() {
|
||||
if (agent.topics.length === 1) return
|
||||
if (assistant.topics.length === 1) return
|
||||
currentTopic.current && removeTopic(currentTopic.current)
|
||||
currentTopic.current = null
|
||||
setActiveTopic(agent.topics[0])
|
||||
setActiveTopic(assistant.topics[0])
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -77,7 +77,7 @@ const TopicList: FC<Props> = ({ agent, activeTopic, setActiveTopic }) => {
|
||||
return (
|
||||
<Container className={showRightSidebar ? '' : 'collapsed'}>
|
||||
<TopicTitle>
|
||||
<span>Topics ({agent.topics.length})</span>
|
||||
<span>Topics ({assistant.topics.length})</span>
|
||||
<Popconfirm
|
||||
icon={false}
|
||||
title="Delete all topic?"
|
||||
@ -92,7 +92,7 @@ const TopicList: FC<Props> = ({ agent, activeTopic, setActiveTopic }) => {
|
||||
</DeleteButton>
|
||||
</Popconfirm>
|
||||
</TopicTitle>
|
||||
{agent.topics.map((topic) => (
|
||||
{assistant.topics.map((topic) => (
|
||||
<Dropdown
|
||||
menu={{ items: topicMenuItems }}
|
||||
trigger={['contextMenu']}
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { FC } from 'react'
|
||||
import styled from 'styled-components'
|
||||
|
||||
const AboutSetting: FC = () => {
|
||||
const AboutSettings: FC = () => {
|
||||
return <Container>About</Container>
|
||||
}
|
||||
|
||||
const Container = styled.div``
|
||||
|
||||
export default AboutSetting
|
||||
export default AboutSettings
|
||||
10
src/renderer/src/pages/settings/CommonSettings.tsx
Normal file
10
src/renderer/src/pages/settings/CommonSettings.tsx
Normal file
@ -0,0 +1,10 @@
|
||||
import { FC } from 'react'
|
||||
import styled from 'styled-components'
|
||||
|
||||
const CommonSettings: FC = () => {
|
||||
return <Container>Common Settings</Container>
|
||||
}
|
||||
|
||||
const Container = styled.div``
|
||||
|
||||
export default CommonSettings
|
||||
@ -1,10 +0,0 @@
|
||||
import { FC } from 'react'
|
||||
import styled from 'styled-components'
|
||||
|
||||
const DefaultAgentSetting: FC = () => {
|
||||
return <Container>Default Agent</Container>
|
||||
}
|
||||
|
||||
const Container = styled.div``
|
||||
|
||||
export default DefaultAgentSetting
|
||||
10
src/renderer/src/pages/settings/DefaultAssistantSetting.tsx
Normal file
10
src/renderer/src/pages/settings/DefaultAssistantSetting.tsx
Normal file
@ -0,0 +1,10 @@
|
||||
import { FC } from 'react'
|
||||
import styled from 'styled-components'
|
||||
|
||||
const DefaultAssistantSetting: FC = () => {
|
||||
return <Container>Default Assistant</Container>
|
||||
}
|
||||
|
||||
const Container = styled.div``
|
||||
|
||||
export default DefaultAssistantSetting
|
||||
@ -1,10 +0,0 @@
|
||||
import { FC } from 'react'
|
||||
import styled from 'styled-components'
|
||||
|
||||
const GeneralSetting: FC = () => {
|
||||
return <Container>General Settings</Container>
|
||||
}
|
||||
|
||||
const Container = styled.div``
|
||||
|
||||
export default GeneralSetting
|
||||
36
src/renderer/src/pages/settings/LanguageModelsSettings.tsx
Normal file
36
src/renderer/src/pages/settings/LanguageModelsSettings.tsx
Normal file
@ -0,0 +1,36 @@
|
||||
import { Collapse } from 'antd'
|
||||
import { FC } from 'react'
|
||||
import styled from 'styled-components'
|
||||
|
||||
const LanguageModelsSettings: FC = () => {
|
||||
return (
|
||||
<Container>
|
||||
<Collapse style={{ width: '100%', marginBottom: 10 }}>
|
||||
<Collapse.Panel header="OpenAI" key="openai">
|
||||
<p>OpenAI</p>
|
||||
</Collapse.Panel>
|
||||
</Collapse>
|
||||
<Collapse style={{ width: '100%', marginBottom: 10 }}>
|
||||
<Collapse.Panel header="Silicon" key="silicon">
|
||||
<p>Silicon</p>
|
||||
</Collapse.Panel>
|
||||
</Collapse>
|
||||
<Collapse style={{ width: '100%', marginBottom: 10 }}>
|
||||
<Collapse.Panel header="deepseek" key="deepseek">
|
||||
<p>deepseek</p>
|
||||
</Collapse.Panel>
|
||||
</Collapse>
|
||||
<Collapse style={{ width: '100%', marginBottom: 10 }}>
|
||||
<Collapse.Panel header="Groq" key="groq">
|
||||
<p>Groq</p>
|
||||
</Collapse.Panel>
|
||||
</Collapse>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
const Container = styled.div`
|
||||
width: 100%;
|
||||
`
|
||||
|
||||
export default LanguageModelsSettings
|
||||
@ -1,10 +0,0 @@
|
||||
import { FC } from 'react'
|
||||
import styled from 'styled-components'
|
||||
|
||||
const ModelsSetting: FC = () => {
|
||||
return <Container>Models</Container>
|
||||
}
|
||||
|
||||
const Container = styled.div``
|
||||
|
||||
export default ModelsSetting
|
||||
@ -2,11 +2,11 @@ import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar'
|
||||
import { FC } from 'react'
|
||||
import { Link, Route, Routes, useLocation } from 'react-router-dom'
|
||||
import styled from 'styled-components'
|
||||
import SettingsHomePage from './GeneralSetting'
|
||||
import SettingsDeveloperPage from './DeveloperSetting'
|
||||
import SettingsAboutPage from './AboutSetting'
|
||||
import SettingsModelsPage from './ModelsSetting'
|
||||
import SettingsDefaultAgent from './DefaultAgentSetting'
|
||||
import CommonSettings from './CommonSettings'
|
||||
import AboutSettings from './AboutSettings'
|
||||
import DefaultAssistantSetting from './DefaultAssistantSetting'
|
||||
import SystemAssistantSettings from './SystemAssistantSettings'
|
||||
import LanguageModelsSettings from './LanguageModelsSettings'
|
||||
|
||||
const SettingsPage: FC = () => {
|
||||
const { pathname } = useLocation()
|
||||
@ -20,29 +20,29 @@ const SettingsPage: FC = () => {
|
||||
</Navbar>
|
||||
<ContentContainer>
|
||||
<SettingMenus>
|
||||
<MenuItemLink to="/settings/general">
|
||||
<MenuItem className={isRoute('/settings/general')}>General</MenuItem>
|
||||
<MenuItemLink to="/settings/common">
|
||||
<MenuItem className={isRoute('/settings/common')}>Common Settings</MenuItem>
|
||||
</MenuItemLink>
|
||||
<MenuItemLink to="/settings/models">
|
||||
<MenuItem className={isRoute('/settings/models')}>Language Model</MenuItem>
|
||||
<MenuItemLink to="/settings/llm">
|
||||
<MenuItem className={isRoute('/settings/llm')}>Language Model</MenuItem>
|
||||
</MenuItemLink>
|
||||
<MenuItemLink to="/settings/default-agent">
|
||||
<MenuItem className={isRoute('/settings/default-agent')}>Default Agent</MenuItem>
|
||||
<MenuItemLink to="/settings/system-assistant">
|
||||
<MenuItem className={isRoute('/settings/system-assistant')}>System Assistant</MenuItem>
|
||||
</MenuItemLink>
|
||||
<MenuItemLink to="/settings/default-assistant">
|
||||
<MenuItem className={isRoute('/settings/default-assistant')}>Default Assistant</MenuItem>
|
||||
</MenuItemLink>
|
||||
<MenuItemLink to="/settings/about">
|
||||
<MenuItem className={isRoute('/settings/about')}>About</MenuItem>
|
||||
</MenuItemLink>
|
||||
<MenuItemLink to="/settings/developer">
|
||||
<MenuItem className={isRoute('/settings/developer')}>Developer</MenuItem>
|
||||
</MenuItemLink>
|
||||
</SettingMenus>
|
||||
<SettingContent>
|
||||
<Routes>
|
||||
<Route path="general" element={<SettingsHomePage />} />
|
||||
<Route path="models" element={<SettingsModelsPage />} />
|
||||
<Route path="default-agent" element={<SettingsDefaultAgent />} />
|
||||
<Route path="about" element={<SettingsAboutPage />} />
|
||||
<Route path="developer" element={<SettingsDeveloperPage />} />
|
||||
<Route path="common" element={<CommonSettings />} />
|
||||
<Route path="system-assistant" element={<SystemAssistantSettings />} />
|
||||
<Route path="default-assistant" element={<DefaultAssistantSetting />} />
|
||||
<Route path="llm" element={<LanguageModelsSettings />} />
|
||||
<Route path="about" element={<AboutSettings />} />
|
||||
</Routes>
|
||||
</SettingContent>
|
||||
</ContentContainer>
|
||||
@ -65,7 +65,7 @@ const ContentContainer = styled.div`
|
||||
const SettingMenus = styled.ul`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: var(--agents-width);
|
||||
min-width: var(--assistants-width);
|
||||
border-right: 1px solid var(--color-border);
|
||||
padding: 10px;
|
||||
`
|
||||
@ -84,10 +84,11 @@ const MenuItem = styled.li`
|
||||
font-size: 14px;
|
||||
transition: all 0.2s ease-in-out;
|
||||
&:hover {
|
||||
background: #213675;
|
||||
background: #135200;
|
||||
}
|
||||
&.active {
|
||||
background: #213675;
|
||||
background: #135200;
|
||||
font-weight: bold;
|
||||
}
|
||||
`
|
||||
|
||||
|
||||
10
src/renderer/src/pages/settings/SystemAssistantSettings.tsx
Normal file
10
src/renderer/src/pages/settings/SystemAssistantSettings.tsx
Normal file
@ -0,0 +1,10 @@
|
||||
import { FC } from 'react'
|
||||
import styled from 'styled-components'
|
||||
|
||||
const SystemAssistantSettings: FC = () => {
|
||||
return <Container>System Assistant</Container>
|
||||
}
|
||||
|
||||
const Container = styled.div``
|
||||
|
||||
export default SystemAssistantSettings
|
||||
@ -1,12 +0,0 @@
|
||||
import { Agent } from '@renderer/types'
|
||||
import { getDefaultTopic } from './topic'
|
||||
|
||||
export function getDefaultAgent(): Agent {
|
||||
return {
|
||||
id: 'default',
|
||||
name: 'Default Agent',
|
||||
description: "Hello, I'm Default Agent.",
|
||||
prompt: '',
|
||||
topics: [getDefaultTopic()]
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
import { Agent, Message, Topic } from '@renderer/types'
|
||||
import { Assistant, Message, Topic } from '@renderer/types'
|
||||
import { openaiProvider } from './provider'
|
||||
import { uuid } from '@renderer/utils'
|
||||
import { EVENT_NAMES, EventEmitter } from './event'
|
||||
@ -6,16 +6,16 @@ import { ChatCompletionMessageParam, ChatCompletionSystemMessageParam } from 'op
|
||||
|
||||
interface FetchChatCompletionParams {
|
||||
message: Message
|
||||
agent: Agent
|
||||
assistant: Assistant
|
||||
topic: Topic
|
||||
onResponse: (message: Message) => void
|
||||
}
|
||||
|
||||
export async function fetchChatCompletion({ message, agent, topic, onResponse }: FetchChatCompletionParams) {
|
||||
export async function fetchChatCompletion({ message, assistant, topic, onResponse }: FetchChatCompletionParams) {
|
||||
const stream = await openaiProvider.chat.completions.create({
|
||||
model: 'Qwen/Qwen2-7B-Instruct',
|
||||
messages: [
|
||||
{ role: 'system', content: agent.prompt },
|
||||
{ role: 'system', content: assistant.prompt },
|
||||
{ role: 'user', content: message.content }
|
||||
],
|
||||
stream: true
|
||||
@ -23,9 +23,9 @@ export async function fetchChatCompletion({ message, agent, topic, onResponse }:
|
||||
|
||||
const _message: Message = {
|
||||
id: uuid(),
|
||||
role: 'agent',
|
||||
role: 'assistant',
|
||||
content: '',
|
||||
agentId: agent.id,
|
||||
assistantId: assistant.id,
|
||||
topicId: topic.id,
|
||||
createdAt: 'now'
|
||||
}
|
||||
|
||||
12
src/renderer/src/services/assistant.ts
Normal file
12
src/renderer/src/services/assistant.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { Assistant } from '@renderer/types'
|
||||
import { getDefaultTopic } from './topic'
|
||||
|
||||
export function getDefaultAssistant(): Assistant {
|
||||
return {
|
||||
id: 'default',
|
||||
name: 'Default Assistant',
|
||||
description: "Hello, I'm Default Assistant.",
|
||||
prompt: '',
|
||||
topics: [getDefaultTopic()]
|
||||
}
|
||||
}
|
||||
@ -1,77 +0,0 @@
|
||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
||||
import { getDefaultAgent } from '@renderer/services/agent'
|
||||
import LocalStorage from '@renderer/services/storage'
|
||||
import { getDefaultTopic } from '@renderer/services/topic'
|
||||
import { Agent, Topic } from '@renderer/types'
|
||||
import { uniqBy } from 'lodash'
|
||||
|
||||
export interface AgentsState {
|
||||
agents: Agent[]
|
||||
}
|
||||
|
||||
const initialState: AgentsState = {
|
||||
agents: [getDefaultAgent()]
|
||||
}
|
||||
|
||||
const agentsSlice = createSlice({
|
||||
name: 'agents',
|
||||
initialState,
|
||||
reducers: {
|
||||
addAgent: (state, action: PayloadAction<Agent>) => {
|
||||
state.agents.push(action.payload)
|
||||
},
|
||||
removeAgent: (state, action: PayloadAction<{ id: string }>) => {
|
||||
state.agents = state.agents.filter((c) => c.id !== action.payload.id)
|
||||
},
|
||||
updateAgent: (state, action: PayloadAction<Agent>) => {
|
||||
state.agents = state.agents.map((c) => (c.id === action.payload.id ? action.payload : c))
|
||||
},
|
||||
addTopic: (state, action: PayloadAction<{ agentId: string; topic: Topic }>) => {
|
||||
state.agents = state.agents.map((agent) =>
|
||||
agent.id === action.payload.agentId
|
||||
? {
|
||||
...agent,
|
||||
topics: uniqBy([action.payload.topic, ...agent.topics], 'id')
|
||||
}
|
||||
: agent
|
||||
)
|
||||
},
|
||||
removeTopic: (state, action: PayloadAction<{ agentId: string; topic: Topic }>) => {
|
||||
state.agents = state.agents.map((agent) =>
|
||||
agent.id === action.payload.agentId
|
||||
? {
|
||||
...agent,
|
||||
topics: agent.topics.filter(({ id }) => id !== action.payload.topic.id)
|
||||
}
|
||||
: agent
|
||||
)
|
||||
},
|
||||
updateTopic: (state, action: PayloadAction<{ agentId: string; topic: Topic }>) => {
|
||||
state.agents = state.agents.map((agent) =>
|
||||
agent.id === action.payload.agentId
|
||||
? {
|
||||
...agent,
|
||||
topics: agent.topics.map((topic) => (topic.id === action.payload.topic.id ? action.payload.topic : topic))
|
||||
}
|
||||
: agent
|
||||
)
|
||||
},
|
||||
removeAllTopics: (state, action: PayloadAction<{ agentId: string }>) => {
|
||||
state.agents = state.agents.map((agent) => {
|
||||
if (agent.id === action.payload.agentId) {
|
||||
agent.topics.forEach((topic) => LocalStorage.removeTopic(topic.id))
|
||||
return {
|
||||
...agent,
|
||||
topics: [getDefaultTopic()]
|
||||
}
|
||||
}
|
||||
return agent
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export const { addAgent, removeAgent, updateAgent, addTopic, removeTopic, updateTopic, removeAllTopics } =
|
||||
agentsSlice.actions
|
||||
|
||||
export default agentsSlice.reducer
|
||||
79
src/renderer/src/store/assistants.ts
Normal file
79
src/renderer/src/store/assistants.ts
Normal file
@ -0,0 +1,79 @@
|
||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
||||
import { getDefaultAssistant } from '@renderer/services/assistant'
|
||||
import LocalStorage from '@renderer/services/storage'
|
||||
import { getDefaultTopic } from '@renderer/services/topic'
|
||||
import { Assistant, Topic } from '@renderer/types'
|
||||
import { uniqBy } from 'lodash'
|
||||
|
||||
export interface AssistantsState {
|
||||
assistants: Assistant[]
|
||||
}
|
||||
|
||||
const initialState: AssistantsState = {
|
||||
assistants: [getDefaultAssistant()]
|
||||
}
|
||||
|
||||
const assistantsSlice = createSlice({
|
||||
name: 'assistants',
|
||||
initialState,
|
||||
reducers: {
|
||||
addAssistant: (state, action: PayloadAction<Assistant>) => {
|
||||
state.assistants.push(action.payload)
|
||||
},
|
||||
removeAssistant: (state, action: PayloadAction<{ id: string }>) => {
|
||||
state.assistants = state.assistants.filter((c) => c.id !== action.payload.id)
|
||||
},
|
||||
updateAssistant: (state, action: PayloadAction<Assistant>) => {
|
||||
state.assistants = state.assistants.map((c) => (c.id === action.payload.id ? action.payload : c))
|
||||
},
|
||||
addTopic: (state, action: PayloadAction<{ assistantId: string; topic: Topic }>) => {
|
||||
state.assistants = state.assistants.map((assistant) =>
|
||||
assistant.id === action.payload.assistantId
|
||||
? {
|
||||
...assistant,
|
||||
topics: uniqBy([action.payload.topic, ...assistant.topics], 'id')
|
||||
}
|
||||
: assistant
|
||||
)
|
||||
},
|
||||
removeTopic: (state, action: PayloadAction<{ assistantId: string; topic: Topic }>) => {
|
||||
state.assistants = state.assistants.map((assistant) =>
|
||||
assistant.id === action.payload.assistantId
|
||||
? {
|
||||
...assistant,
|
||||
topics: assistant.topics.filter(({ id }) => id !== action.payload.topic.id)
|
||||
}
|
||||
: assistant
|
||||
)
|
||||
},
|
||||
updateTopic: (state, action: PayloadAction<{ assistantId: string; topic: Topic }>) => {
|
||||
state.assistants = state.assistants.map((assistant) =>
|
||||
assistant.id === action.payload.assistantId
|
||||
? {
|
||||
...assistant,
|
||||
topics: assistant.topics.map((topic) =>
|
||||
topic.id === action.payload.topic.id ? action.payload.topic : topic
|
||||
)
|
||||
}
|
||||
: assistant
|
||||
)
|
||||
},
|
||||
removeAllTopics: (state, action: PayloadAction<{ assistantId: string }>) => {
|
||||
state.assistants = state.assistants.map((assistant) => {
|
||||
if (assistant.id === action.payload.assistantId) {
|
||||
assistant.topics.forEach((topic) => LocalStorage.removeTopic(topic.id))
|
||||
return {
|
||||
...assistant,
|
||||
topics: [getDefaultTopic()]
|
||||
}
|
||||
}
|
||||
return assistant
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export const { addAssistant, removeAssistant, updateAssistant, addTopic, removeTopic, updateTopic, removeAllTopics } =
|
||||
assistantsSlice.actions
|
||||
|
||||
export default assistantsSlice.reducer
|
||||
@ -2,11 +2,11 @@ import { combineReducers, configureStore } from '@reduxjs/toolkit'
|
||||
import { useDispatch, useSelector, useStore } from 'react-redux'
|
||||
import { FLUSH, PAUSE, PERSIST, persistReducer, persistStore, PURGE, REGISTER, REHYDRATE } from 'redux-persist'
|
||||
import storage from 'redux-persist/lib/storage'
|
||||
import agents from './agents'
|
||||
import assistants from './assistants'
|
||||
import settings from './settings'
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
agents,
|
||||
assistants,
|
||||
settings
|
||||
})
|
||||
|
||||
|
||||
31
src/renderer/src/store/llm.ts
Normal file
31
src/renderer/src/store/llm.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { createSlice } from '@reduxjs/toolkit'
|
||||
|
||||
type Provider = {
|
||||
id: string
|
||||
name: string
|
||||
apiKey: string
|
||||
apiUrl: string
|
||||
url: string
|
||||
}
|
||||
|
||||
export interface LlmState {
|
||||
providers: Provider[]
|
||||
}
|
||||
|
||||
const initialState: LlmState = {
|
||||
providers: []
|
||||
}
|
||||
|
||||
const settingsSlice = createSlice({
|
||||
name: 'settings',
|
||||
initialState,
|
||||
reducers: {
|
||||
updateProvider: () => {
|
||||
//
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export const { updateProvider } = settingsSlice.actions
|
||||
|
||||
export default settingsSlice.reducer
|
||||
@ -1,4 +1,4 @@
|
||||
export type Agent = {
|
||||
export type Assistant = {
|
||||
id: string
|
||||
name: string
|
||||
description: string
|
||||
@ -8,9 +8,9 @@ export type Agent = {
|
||||
|
||||
export type Message = {
|
||||
id: string
|
||||
role: 'user' | 'agent'
|
||||
role: 'user' | 'assistant'
|
||||
content: string
|
||||
agentId: string
|
||||
assistantId: string
|
||||
topicId: string
|
||||
createdAt: string
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user