diff --git a/package.json b/package.json index 8ac046f1..710ec8c0 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "@fontsource/inter": "^5.0.18", "@reduxjs/toolkit": "^2.2.5", "antd": "^5.18.3", + "dayjs": "^1.11.11", "electron-updater": "^6.1.7", "electron-window-state": "^5.0.3", "emittery": "^1.0.3", diff --git a/src/renderer/src/assets/styles/index.scss b/src/renderer/src/assets/styles/index.scss index 91b74c0e..b2fa7df5 100644 --- a/src/renderer/src/assets/styles/index.scss +++ b/src/renderer/src/assets/styles/index.scss @@ -1,4 +1,4 @@ -@import 'https://at.alicdn.com/t/c/font_4563475_yuh5d3ftmm.css'; +@import 'https://at.alicdn.com/t/c/font_4563475_hrx8c92awui.css'; @import './markdown.scss'; :root { --color-white: #ffffff; @@ -27,9 +27,10 @@ --navbar-height: 40px; --sidebar-width: 70px; - --conversations-width: 240px; + --agents-width: 240px; --settings-width: 280px; --status-bar-height: 40px; + --input-bar-height: 120px; } *, diff --git a/src/renderer/src/assets/styles/markdown.scss b/src/renderer/src/assets/styles/markdown.scss index 896b3cec..6debd3c0 100644 --- a/src/renderer/src/assets/styles/markdown.scss +++ b/src/renderer/src/assets/styles/markdown.scss @@ -1,6 +1,4 @@ .markdown { - width: 100%; - max-width: 800px; color: #fff; font-size: 14px; line-height: 1.6; @@ -79,6 +77,14 @@ background-color: #555; } + pre { + white-space: pre-wrap; + } + + span { + word-break: break-all; + } + code { font-weight: 600; padding: 3px 5px; @@ -92,5 +98,6 @@ Liberation Mono, monospace; font-size: 80%; + display: inline-block; } } diff --git a/src/renderer/src/components/app/Navbar.tsx b/src/renderer/src/components/app/Navbar.tsx index 3c037473..4ccb1caa 100644 --- a/src/renderer/src/components/app/Navbar.tsx +++ b/src/renderer/src/components/app/Navbar.tsx @@ -31,7 +31,7 @@ const NavbarContainer = styled.div` ` const NavbarLeftContainer = styled.div` - min-width: var(--conversations-width); + min-width: var(--agents-width); border-right: 1px solid #ffffff20; padding: 0 16px; display: flex; diff --git a/src/renderer/src/components/app/Statusbar.tsx b/src/renderer/src/components/app/Statusbar.tsx index ef109005..9c2703c7 100644 --- a/src/renderer/src/components/app/Statusbar.tsx +++ b/src/renderer/src/components/app/Statusbar.tsx @@ -24,7 +24,7 @@ const Container = styled.div` ` const StatusbarLeft = styled.div` - min-width: var(--sidebar-width) + var(--conversations-width); + min-width: var(--sidebar-width) + var(--agents-width); ` const StatusbarCenter = styled.div` diff --git a/src/renderer/src/hooks/useAgents.ts b/src/renderer/src/hooks/useAgents.ts index 2f01445e..f217736f 100644 --- a/src/renderer/src/hooks/useAgents.ts +++ b/src/renderer/src/hooks/useAgents.ts @@ -7,6 +7,7 @@ import { updateAgent } from '@renderer/store/agents' import { Agent } from '@renderer/types' +import localforage from 'localforage' export default function useAgents() { const { agents } = useAppSelector((state) => state.agents) @@ -15,7 +16,13 @@ export default function useAgents() { return { agents, addAgent: (agent: Agent) => dispatch(addAgent(agent)), - removeAgent: (id: string) => dispatch(removeAgent({ id })), + removeAgent: (id: string) => { + dispatch(removeAgent({ id })) + const agent = agents.find((a) => a.id === id) + if (agent) { + agent.conversations.forEach((id) => localforage.removeItem(`conversation:${id}`)) + } + }, updateAgent: (agent: Agent) => dispatch(updateAgent(agent)), addConversation: (agentId: string, conversationId: string) => { dispatch(addConversationToAgent({ agentId, conversationId })) diff --git a/src/renderer/src/pages/home/HomePage.tsx b/src/renderer/src/pages/home/HomePage.tsx index 0c884f77..48bc3f43 100644 --- a/src/renderer/src/pages/home/HomePage.tsx +++ b/src/renderer/src/pages/home/HomePage.tsx @@ -5,36 +5,24 @@ import styled from 'styled-components' import Chat from './components/Chat' import Agents from './components/Agents' import { uuid } from '@renderer/utils' -import { Agent } from '@renderer/types' -import { last } from 'lodash' +import { getDefaultAgent } from '@renderer/services/agent' const HomePage: FC = () => { const { agents, addAgent } = useAgents() const [activeAgent, setActiveAgent] = useState(agents[0]) - const onCreateConversation = () => { - const _agent = { - id: uuid(), - name: 'New conversation', - avatar: 'https://www.gravatar.com/avatar/00000000000000000000000000000000?d=mp&f=y', - lastMessage: 'message', - lastMessageAt: 'now', - conversations: [] - } + const onCreateAgent = () => { + const _agent = getDefaultAgent() + _agent.id = uuid() addAgent(_agent) setActiveAgent(_agent) } - const onRemoveAgent = (agent: Agent) => { - const _agent = last(agents.filter((a) => a.id !== agent.id)) - _agent && setActiveAgent(_agent) - } - return ( - + @@ -46,7 +34,7 @@ const HomePage: FC = () => { - + diff --git a/src/renderer/src/pages/home/components/Agents.tsx b/src/renderer/src/pages/home/components/Agents.tsx index cd2c2b2b..2f752ed6 100644 --- a/src/renderer/src/pages/home/components/Agents.tsx +++ b/src/renderer/src/pages/home/components/Agents.tsx @@ -4,20 +4,23 @@ import useAgents from '@renderer/hooks/useAgents' import { Agent } from '@renderer/types' import { Dropdown, MenuProps } from 'antd' import { EllipsisOutlined } from '@ant-design/icons' +import { last } from 'lodash' interface Props { activeAgent: Agent onActive: (agent: Agent) => void - onRemove: (agent: Agent) => void } -const Agents: FC = ({ activeAgent, onActive, onRemove }) => { +const Agents: FC = ({ activeAgent, onActive }) => { const { agents, removeAgent } = useAgents() const targetAgent = useRef(null) const onDelete = (agent: Agent) => { removeAgent(agent.id) - onRemove(agent) + setTimeout(() => { + const _agent = last(agents.filter((a) => a.id !== agent.id)) + _agent && onActive(_agent) + }, 0) } const items: MenuProps['items'] = [ @@ -36,14 +39,17 @@ const Agents: FC = ({ activeAgent, onActive, onRemove }) => { } ] + console.debug('activeAgent', activeAgent) + return ( {agents.map((agent) => ( onActive(agent)} className={agent.id === activeAgent?.id ? 'active' : ''}> - + { @@ -53,8 +59,7 @@ const Agents: FC = ({ activeAgent, onActive, onRemove }) => { /> {agent.name} - {agent.lastMessage} - {agent.lastMessageAt} + {agent.description} ))} @@ -64,8 +69,8 @@ const Agents: FC = ({ activeAgent, onActive, onRemove }) => { const Container = styled.div` display: flex; flex-direction: column; - min-width: var(--conversations-width); - max-width: var(--conversations-width); + min-width: var(--agents-width); + max-width: var(--agents-width); border-right: 0.5px solid #ffffff20; height: calc(100vh - var(--navbar-height)); overflow-y: scroll; @@ -95,11 +100,6 @@ const AgentItem = styled.div` } ` -const AgentTime = styled.div` - font-size: 12px; - color: var(--color-text-2); -` - const AgentName = styled.div` font-size: 14px; color: var(--color-text-1); diff --git a/src/renderer/src/pages/home/components/Conversations.tsx b/src/renderer/src/pages/home/components/Conversations.tsx index e94947b2..2f75f15e 100644 --- a/src/renderer/src/pages/home/components/Conversations.tsx +++ b/src/renderer/src/pages/home/components/Conversations.tsx @@ -43,6 +43,7 @@ const Conversations: FC = ({ agent, conversationId }) => { const _message: Message = { id: uuid(), + role: 'agent', content: '', agentId: agent.id, conversationId, @@ -82,7 +83,6 @@ const Conversations: FC = ({ agent, conversationId }) => { useEffect(() => { runAsyncFunction(async () => { const conversation = await localforage.getItem(`conversation:${conversationId}`) - console.debug('conversation', conversation) setMessages(conversation ? conversation.messages : []) }) }, [conversationId]) @@ -102,6 +102,7 @@ const Container = styled.div` flex-direction: column; overflow-y: scroll; flex-direction: column-reverse; + max-height: calc(100vh - var(--input-bar-height) - var(--navbar-height)); &::-webkit-scrollbar { display: none; } diff --git a/src/renderer/src/pages/home/components/Inputbar.tsx b/src/renderer/src/pages/home/components/Inputbar.tsx index 9d412dce..3708b4dd 100644 --- a/src/renderer/src/pages/home/components/Inputbar.tsx +++ b/src/renderer/src/pages/home/components/Inputbar.tsx @@ -3,6 +3,8 @@ import { Agent, Message } 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 { Tooltip } from 'antd' interface Props { agent: Agent @@ -17,6 +19,7 @@ const Inputbar: FC = ({ agent }) => { const message: Message = { id: uuid(), + role: 'user', content: text, agentId: agent.id, conversationId, @@ -31,28 +34,100 @@ const Inputbar: FC = ({ agent }) => { } return ( -