From b573e8cab1ce4d46f1d5fc718b114bb7ea0224ba Mon Sep 17 00:00:00 2001 From: Robin Goetz <35136007+goetzrobin@users.noreply.github.com> Date: Mon, 18 Dec 2023 19:41:23 +0100 Subject: [PATCH] feat: next iteration of chatui (#642) * feat: add dark mode & make minor UI improvements added dark mode toggle & picked a color scheme that is closer to the memgpt icons cleaned up the home page a little bit. * feat: add thinking indicator & make minor UI improvements we now show a thinking while the current message is loading. removed status indicator as we do not work with websockets anymore. also adjusted some of the chat styles to better fit the new theme. * feat: add memory viewer and allow memory edit * chore: build frontend --- memgpt-frontend/index.html | 21 +++ memgpt-frontend/src/app/app.tsx | 13 +- .../app/libs/agents/agent-memory-update.ts | 10 ++ .../libs/agents/use-agent-memory.mutation.ts | 20 +++ .../app/libs/messages/message-stream.store.ts | 6 +- .../messages/next-message-loading.store.ts | 16 --- memgpt-frontend/src/app/modules/chat/chat.tsx | 5 +- .../modules/chat/memory-view/memory-form.tsx | 87 ++++++++++++ .../modules/chat/memory-view/memory-view.tsx | 33 +++++ .../messages/message-container-layout.tsx | 2 +- .../chat/messages/message-container.tsx | 8 +- .../chat/messages/message/user-message.tsx | 4 +- .../chat/messages/status-indicator.tsx | 19 --- .../src/app/modules/chat/user-input.tsx | 21 +-- .../src/app/modules/home/agent-card.tsx | 2 +- memgpt-frontend/src/app/modules/home/home.tsx | 21 ++- .../src/app/shared/layout/header.tsx | 16 ++- memgpt-frontend/src/app/shared/theme.tsx | 48 +++++++ memgpt-frontend/src/styles.css | 85 +++++------- memgpt/server/rest_api/agents/memory.py | 2 +- memgpt/server/server.py | 2 +- .../static_files/assets/index-156e79f0.js | 129 ++++++++++++++++++ .../static_files/assets/index-3436ea62.js | 129 ------------------ .../static_files/assets/index-5cf8a11d.css | 1 - .../static_files/assets/index-fc829661.css | 1 + memgpt/server/static_files/index.html | 25 +++- 26 files changed, 461 insertions(+), 265 deletions(-) create mode 100644 memgpt-frontend/src/app/libs/agents/agent-memory-update.ts create mode 100644 memgpt-frontend/src/app/libs/agents/use-agent-memory.mutation.ts delete mode 100644 memgpt-frontend/src/app/libs/messages/next-message-loading.store.ts create mode 100644 memgpt-frontend/src/app/modules/chat/memory-view/memory-form.tsx create mode 100644 memgpt-frontend/src/app/modules/chat/memory-view/memory-view.tsx delete mode 100644 memgpt-frontend/src/app/modules/chat/messages/status-indicator.tsx create mode 100644 memgpt-frontend/src/app/shared/theme.tsx create mode 100644 memgpt/server/static_files/assets/index-156e79f0.js delete mode 100644 memgpt/server/static_files/assets/index-3436ea62.js delete mode 100644 memgpt/server/static_files/assets/index-5cf8a11d.css create mode 100644 memgpt/server/static_files/assets/index-fc829661.css diff --git a/memgpt-frontend/index.html b/memgpt-frontend/index.html index 0ab06762..cb1382c7 100644 --- a/memgpt-frontend/index.html +++ b/memgpt-frontend/index.html @@ -8,6 +8,27 @@ +
diff --git a/memgpt-frontend/src/app/app.tsx b/memgpt-frontend/src/app/app.tsx index bd58e726..474bea7e 100644 --- a/memgpt-frontend/src/app/app.tsx +++ b/memgpt-frontend/src/app/app.tsx @@ -8,24 +8,21 @@ import { useMessageSocketActions } from './libs/messages/message-stream.store'; import { useCurrentAgent } from './libs/agents/agent.store'; import { useMessageHistoryActions } from './libs/messages/message-history.store'; import { Message } from './libs/messages/message'; -import { useNextMessageLoadingActions } from './libs/messages/next-message-loading.store'; -import { useAgentMemoryQuery } from './libs/agents/use-agent-memory.query'; +import { ThemeProvider } from './shared/theme'; const queryClient = new QueryClient(); export function App() { const { setAgentParam, registerOnMessageCallback, resetSocket } = useMessageSocketActions(); const { addMessage } =useMessageHistoryActions() - const { setLoading } = useNextMessageLoadingActions() const currentAgent = useCurrentAgent(); useEffect(() => registerOnMessageCallback((message: Message) => { - setLoading(message['type'] === 'agent_response_start'); if (currentAgent) { addMessage(currentAgent.name, message); } - }), [registerOnMessageCallback, currentAgent, setLoading, addMessage]); + }), [registerOnMessageCallback, currentAgent, addMessage]); useEffect(() => { if (!currentAgent) return; @@ -38,9 +35,11 @@ export function App() { return ( - + + + + - ); } diff --git a/memgpt-frontend/src/app/libs/agents/agent-memory-update.ts b/memgpt-frontend/src/app/libs/agents/agent-memory-update.ts new file mode 100644 index 00000000..7709517b --- /dev/null +++ b/memgpt-frontend/src/app/libs/agents/agent-memory-update.ts @@ -0,0 +1,10 @@ +import { z } from 'zod'; + +export const AgentMemoryUpdateSchema = z.object({ + persona: z.string(), + human: z.string(), + user_id: z.string(), + agent_id: z.string() +}) + +export type AgentMemoryUpdate = z.infer; diff --git a/memgpt-frontend/src/app/libs/agents/use-agent-memory.mutation.ts b/memgpt-frontend/src/app/libs/agents/use-agent-memory.mutation.ts new file mode 100644 index 00000000..64a198a1 --- /dev/null +++ b/memgpt-frontend/src/app/libs/agents/use-agent-memory.mutation.ts @@ -0,0 +1,20 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { AgentMemoryUpdate } from './agent-memory-update'; +import { API_BASE_URL } from '../constants'; + +export const useAgentMemoryUpdateMutation = () => { + const queryClient = useQueryClient(); + return useMutation( + { + mutationFn: + async (params: AgentMemoryUpdate) => + await fetch(API_BASE_URL + `/agents/memory`, { + method: 'POST', + headers: { 'Content-Type': ' application/json' }, + body: JSON.stringify(params), + }) + .then(res => res.json()), + onSuccess: (res, { agent_id }) => + queryClient.invalidateQueries({ queryKey: ['agents', agent_id, 'memory'] }), + }); +}; diff --git a/memgpt-frontend/src/app/libs/messages/message-stream.store.ts b/memgpt-frontend/src/app/libs/messages/message-stream.store.ts index 6776e057..68b7c67b 100644 --- a/memgpt-frontend/src/app/libs/messages/message-stream.store.ts +++ b/memgpt-frontend/src/app/libs/messages/message-stream.store.ts @@ -22,8 +22,11 @@ const useMessageStreamStore = create(combine({ actions: { setAgentParam: (agentParam: string) => set(state => ({ ...state, agentParam })), sendMessage: (message: string) => { + set(state => ({ ...state, readyState: ReadyState.LOADING })) + const agent_id = get().agentParam; const onMessageCallback = get().onMessageCallback; + const onCloseCb = () => set(state => ({ ...state, readyState: ReadyState.IDLE })); const onSuccessCb = () => set(state => ({ ...state, readyState: ReadyState.IDLE })) const onOpenCb = () => set(state => ({ ...state, readyState: ReadyState.LOADING })) const errorCb = () => set(state => ({ ...state, readyState: ReadyState.ERROR })) @@ -62,6 +65,7 @@ const useMessageStreamStore = create(combine({ message_type: 'assistant_message', message: parsedData['assistant_message'], }) + onSuccessCb(); } else if (parsedData['function_call'] != null) { onMessageCallback({ type: 'agent_response', @@ -75,10 +79,10 @@ const useMessageStreamStore = create(combine({ message: parsedData['function_return'], }) } - onSuccessCb(); }, onclose() { console.log('Connection closed by the server'); + onCloseCb(); }, onerror(err) { console.log('There was an error from server', err); diff --git a/memgpt-frontend/src/app/libs/messages/next-message-loading.store.ts b/memgpt-frontend/src/app/libs/messages/next-message-loading.store.ts deleted file mode 100644 index a9b739f8..00000000 --- a/memgpt-frontend/src/app/libs/messages/next-message-loading.store.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { create } from 'zustand'; -import { combine } from 'zustand/middleware'; - -const useNextMessageLoadingStore = create(combine({ - isLoading: false, - }, - (set) => ({ - actions: { - setLoading: (isLoading: boolean) => set(() => ({ isLoading })), - }, - }))); - -export const useNextMessageLoading = () => useNextMessageLoadingStore(s => s.isLoading); - -export const useNextMessageLoadingActions = () => - useNextMessageLoadingStore((s) => s.actions); diff --git a/memgpt-frontend/src/app/modules/chat/chat.tsx b/memgpt-frontend/src/app/modules/chat/chat.tsx index 42799aeb..8a5490be 100644 --- a/memgpt-frontend/src/app/modules/chat/chat.tsx +++ b/memgpt-frontend/src/app/modules/chat/chat.tsx @@ -7,15 +7,12 @@ import { useMessageStreamReadyState, } from '../../libs/messages/message-stream.store'; import { - useMessageHistory, useMessageHistoryActions, useMessagesForKey, } from '../../libs/messages/message-history.store'; -import { useNextMessageLoading } from '../../libs/messages/next-message-loading.store'; import { useCurrentAgent } from '../../libs/agents/agent.store'; const Chat = () => { - const isThinking = useNextMessageLoading(); const currentAgent = useCurrentAgent(); const messages = useMessagesForKey(currentAgent?.name ?? ''); @@ -34,7 +31,7 @@ const Chat = () => { }; return (
- +
); diff --git a/memgpt-frontend/src/app/modules/chat/memory-view/memory-form.tsx b/memgpt-frontend/src/app/modules/chat/memory-view/memory-form.tsx new file mode 100644 index 00000000..a70c7a76 --- /dev/null +++ b/memgpt-frontend/src/app/modules/chat/memory-view/memory-form.tsx @@ -0,0 +1,87 @@ +import { useForm } from 'react-hook-form'; +import * as z from 'zod'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from '@memgpt/components/form'; +import { Textarea } from '@memgpt/components/textarea'; +import { Button } from '@memgpt/components/button'; +import React from 'react'; +import { AgentMemory } from '../../../libs/agents/agent-memory'; +import { cn } from '@memgpt/utils'; +import { AgentMemoryUpdateSchema } from '../../../libs/agents/agent-memory-update'; +import { useAgentMemoryUpdateMutation } from '../../../libs/agents/use-agent-memory.mutation'; +import { Loader2 } from 'lucide-react'; + + +export function MemoryForm({ data, agentId, className }: { data: AgentMemory; agentId: string, className?: string }) { + const mutation = useAgentMemoryUpdateMutation(); + + const form = useForm>({ + resolver: zodResolver(AgentMemoryUpdateSchema), + defaultValues: { + persona: data.core_memory.persona, + human: data.core_memory.human, + user_id: 'null', + agent_id: agentId + } + }); + + function onSubmit(data: z.infer) { + mutation.mutate(data) + } + + return ( +
+ + ( + + Persona + +