Browse Source

Feat: Multi tab support! (#5370)

Co-authored-by: Robert Brennan <accounts@rbren.io>
tofarr 1 year ago
parent
commit
0dde1602c2

+ 15 - 0
frontend/__tests__/components/chat/chat-interface.test.tsx

@@ -56,6 +56,7 @@ describe("Empty state", () => {
           content: "Hello",
           imageUrls: [],
           timestamp: new Date().toISOString(),
+          pending: true,
         }),
       );
     });
@@ -172,12 +173,14 @@ describe.skip("ChatInterface", () => {
         content: "Hello",
         imageUrls: [],
         timestamp: new Date().toISOString(),
+        pending: true,
       },
       {
         sender: "assistant",
         content: "Hi",
         imageUrls: [],
         timestamp: new Date().toISOString(),
+        pending: true,
       },
     ];
     renderChatInterface(messages);
@@ -211,6 +214,7 @@ describe.skip("ChatInterface", () => {
         content: "Here are some images",
         imageUrls: [],
         timestamp: new Date().toISOString(),
+        pending: true,
       },
     ];
     const { rerender } = renderChatInterface(messages);
@@ -223,6 +227,7 @@ describe.skip("ChatInterface", () => {
         content: "Here are some images",
         imageUrls: ["image1", "image2"],
         timestamp: new Date().toISOString(),
+        pending: true,
       },
     ];
 
@@ -244,12 +249,14 @@ describe.skip("ChatInterface", () => {
         content: "Hello",
         imageUrls: [],
         timestamp: new Date().toISOString(),
+        pending: true,
       },
       {
         sender: "user",
         content: "Hi",
         imageUrls: [],
         timestamp: new Date().toISOString(),
+        pending: true,
       },
     ];
     const { rerender } = renderChatInterface(messages);
@@ -262,6 +269,7 @@ describe.skip("ChatInterface", () => {
       content: "How can I help you?",
       imageUrls: [],
       timestamp: new Date().toISOString(),
+      pending: true,
     });
 
     rerender(<ChatInterface />);
@@ -276,6 +284,7 @@ describe.skip("ChatInterface", () => {
         content: "Hello",
         imageUrls: [],
         timestamp: new Date().toISOString(),
+        pending: true,
       },
       {
         error: true,
@@ -301,6 +310,7 @@ describe.skip("ChatInterface", () => {
         content: "Hello",
         imageUrls: [],
         timestamp: new Date().toISOString(),
+        pending: true,
       },
     ];
     renderChatInterface(messages);
@@ -326,6 +336,7 @@ describe.skip("ChatInterface", () => {
         content: "Hello",
         imageUrls: [],
         timestamp: new Date().toISOString(),
+        pending: true,
       },
     ];
     const { rerender } = renderChatInterface(messages);
@@ -358,18 +369,21 @@ describe.skip("ChatInterface", () => {
         content: "Hello",
         imageUrls: [],
         timestamp: new Date().toISOString(),
+        pending: true,
       },
       {
         sender: "user",
         content: "Hi",
         imageUrls: [],
         timestamp: new Date().toISOString(),
+        pending: true,
       },
       {
         sender: "assistant",
         content: "How can I help you?",
         imageUrls: [],
         timestamp: new Date().toISOString(),
+        pending: true,
       },
     ];
     const { rerender } = renderChatInterface(messages);
@@ -380,6 +394,7 @@ describe.skip("ChatInterface", () => {
       content: "I need help",
       imageUrls: [],
       timestamp: new Date().toISOString(),
+      pending: true,
     });
 
     rerender(<ChatInterface />);

+ 2 - 1
frontend/src/components/features/chat/chat-interface.tsx

@@ -68,7 +68,8 @@ export function ChatInterface() {
     const imageUrls = await Promise.all(promises);
 
     const timestamp = new Date().toISOString();
-    dispatch(addUserMessage({ content, imageUrls, timestamp }));
+    const pending = true;
+    dispatch(addUserMessage({ content, imageUrls, timestamp, pending }));
     send(createChatMessage(content, imageUrls, timestamp));
     setMessageToSend(null);
   };

+ 1 - 0
frontend/src/components/features/project-menu/ProjectMenuCard.tsx

@@ -47,6 +47,7 @@ Please push the changes to GitHub and open a pull request.
 `,
       imageUrls: [],
       timestamp: new Date().toISOString(),
+      pending: false,
     };
     const event = createChatMessage(
       rawEvent.content,

+ 1 - 0
frontend/src/message.d.ts

@@ -3,6 +3,7 @@ type Message = {
   content: string;
   imageUrls: string[];
   timestamp: string;
+  pending?: boolean;
 };
 
 type ErrorMessage = {

+ 1 - 0
frontend/src/routes/_oh.app/hooks/use-ws-status-change.ts

@@ -86,6 +86,7 @@ export const useWSStatusChange = () => {
           content: initialQuery,
           imageUrls: files,
           timestamp: new Date().toISOString(),
+          pending: true,
         }),
       );
     }

+ 1 - 0
frontend/src/services/actions.ts

@@ -47,6 +47,7 @@ const messageActions = {
           content: message.args.content,
           imageUrls: [],
           timestamp: message.timestamp,
+          pending: false,
         }),
       );
     } else {

+ 12 - 0
frontend/src/state/chat-slice.ts

@@ -16,6 +16,7 @@ export const chatSlice = createSlice({
         content: string;
         imageUrls: string[];
         timestamp: string;
+        pending?: boolean;
       }>,
     ) {
       const message: Message = {
@@ -23,7 +24,17 @@ export const chatSlice = createSlice({
         content: action.payload.content,
         imageUrls: action.payload.imageUrls,
         timestamp: action.payload.timestamp || new Date().toISOString(),
+        pending: !!action.payload.pending,
       };
+      // Remove any pending messages
+      let i = state.messages.length;
+      while (i) {
+        i -= 1;
+        const m = state.messages[i] as Message;
+        if (m.pending) {
+          state.messages.splice(i, 1);
+        }
+      }
       state.messages.push(message);
     },
 
@@ -33,6 +44,7 @@ export const chatSlice = createSlice({
         content: action.payload,
         imageUrls: [],
         timestamp: new Date().toISOString(),
+        pending: false,
       };
       state.messages.push(message);
     },

+ 1 - 3
openhands/server/session/session.py

@@ -124,9 +124,7 @@ class Session:
             return
         if event.source == EventSource.AGENT:
             await self.send(event_to_dict(event))
-        elif event.source == EventSource.USER and isinstance(
-            event, CmdOutputObservation
-        ):
+        elif event.source == EventSource.USER:
             await self.send(event_to_dict(event))
         # NOTE: ipython observations are not sent here currently
         elif event.source == EventSource.ENVIRONMENT and isinstance(