diff options
| author | Nate Sesti <sestinj@gmail.com> | 2023-06-02 14:09:50 -0400 | 
|---|---|---|
| committer | Nate Sesti <sestinj@gmail.com> | 2023-06-02 14:09:50 -0400 | 
| commit | 3157898f13a6990aff909e8e4af7f58515a28e8c (patch) | |
| tree | 773ec943df45a679fa4a0f221b871b7248be50d7 /extension/react-app/src | |
| parent | 6b909caa8dcbd4bf3d1078ded1c12146944ab349 (diff) | |
| parent | aea318b48dd7e15df16eca12ba59c677671869aa (diff) | |
| download | sncontinue-3157898f13a6990aff909e8e4af7f58515a28e8c.tar.gz sncontinue-3157898f13a6990aff909e8e4af7f58515a28e8c.tar.bz2 sncontinue-3157898f13a6990aff909e8e4af7f58515a28e8c.zip | |
Merge branch 'main' into docs
Diffstat (limited to 'extension/react-app/src')
| -rw-r--r-- | extension/react-app/src/App.tsx | 6 | ||||
| -rw-r--r-- | extension/react-app/src/components/CodeBlock.tsx | 3 | ||||
| -rw-r--r-- | extension/react-app/src/components/DebugPanel.tsx | 4 | ||||
| -rw-r--r-- | extension/react-app/src/components/StepContainer.tsx | 31 | ||||
| -rw-r--r-- | extension/react-app/src/components/index.ts | 2 | ||||
| -rw-r--r-- | extension/react-app/src/hooks/ContinueGUIClientProtocol.ts | 13 | ||||
| -rw-r--r-- | extension/react-app/src/hooks/messenger.ts | 108 | ||||
| -rw-r--r-- | extension/react-app/src/hooks/useContinueGUIProtocol.ts | 49 | ||||
| -rw-r--r-- | extension/react-app/src/hooks/useWebsocket.ts | 82 | ||||
| -rw-r--r-- | extension/react-app/src/hooks/vscodeMessenger.ts | 71 | ||||
| -rw-r--r-- | extension/react-app/src/index.css | 2 | ||||
| -rw-r--r-- | extension/react-app/src/main.tsx | 25 | ||||
| -rw-r--r-- | extension/react-app/src/tabs/chat/MessageDiv.tsx | 3 | ||||
| -rw-r--r-- | extension/react-app/src/tabs/gui.tsx (renamed from extension/react-app/src/tabs/notebook.tsx) | 90 | ||||
| -rw-r--r-- | extension/react-app/src/vscode/index.ts | 1 | 
15 files changed, 347 insertions, 143 deletions
| diff --git a/extension/react-app/src/App.tsx b/extension/react-app/src/App.tsx index 0c40ced1..a51541d0 100644 --- a/extension/react-app/src/App.tsx +++ b/extension/react-app/src/App.tsx @@ -4,7 +4,7 @@ import { Provider } from "react-redux";  import store from "./redux/store";  import WelcomeTab from "./tabs/welcome";  import ChatTab from "./tabs/chat"; -import Notebook from "./tabs/notebook"; +import GUI from "./tabs/gui";  function App() {    return ( @@ -13,8 +13,8 @@ function App() {          <DebugPanel            tabs={[              { -              element: <Notebook />, -              title: "Notebook", +              element: <GUI />, +              title: "GUI",              },              // { element: <MainTab />, title: "Debug Panel" },              // { element: <WelcomeTab />, title: "Welcome" }, diff --git a/extension/react-app/src/components/CodeBlock.tsx b/extension/react-app/src/components/CodeBlock.tsx index 4c10ab23..e0336554 100644 --- a/extension/react-app/src/components/CodeBlock.tsx +++ b/extension/react-app/src/components/CodeBlock.tsx @@ -6,7 +6,8 @@ import { defaultBorderRadius, vscBackground } from ".";  import { Clipboard } from "@styled-icons/heroicons-outline";  const StyledPre = styled.pre` -  overflow: scroll; +  overflow-y: scroll; +  word-wrap: normal;    border: 1px solid gray;    border-radius: ${defaultBorderRadius};    background-color: ${vscBackground}; diff --git a/extension/react-app/src/components/DebugPanel.tsx b/extension/react-app/src/components/DebugPanel.tsx index ed00571b..9dacc624 100644 --- a/extension/react-app/src/components/DebugPanel.tsx +++ b/extension/react-app/src/components/DebugPanel.tsx @@ -36,7 +36,8 @@ const GradientContainer = styled.div`  const MainDiv = styled.div`    height: 100%;    border-radius: ${defaultBorderRadius}; -  overflow: scroll; +  overflow-y: scroll; +  scrollbar-gutter: stable both-edges;    scrollbar-base-color: transparent;    /* background: ${vscBackground}; */    background-color: #1e1e1ede; @@ -107,6 +108,7 @@ function DebugPanel(props: DebugPanelProps) {                  className={                    tab.title === "Chat" ? "overflow-hidden" : "overflow-scroll"                  } +                style={{ scrollbarGutter: "stable both-edges" }}                >                  {tab.element}                </div> diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx index 03649b66..5e979b34 100644 --- a/extension/react-app/src/components/StepContainer.tsx +++ b/extension/react-app/src/components/StepContainer.tsx @@ -36,6 +36,8 @@ const MainDiv = styled.div<{ stepDepth: number; inFuture: boolean }>`    animation: ${appear} 0.3s ease-in-out;    /* padding-left: ${(props) => props.stepDepth * 20}px; */    overflow: hidden; +  margin-left: 0px; +  margin-right: 0px;  `;  const StepContainerDiv = styled.div<{ open: boolean }>` @@ -78,6 +80,13 @@ function StepContainer(props: StepContainerProps) {    const [open, setOpen] = useState(false);    const [isHovered, setIsHovered] = useState(false);    const naturalLanguageInputRef = useRef<HTMLTextAreaElement>(null); +  const userInputRef = useRef<HTMLInputElement>(null); + +  useEffect(() => { +    if (userInputRef?.current) { +      userInputRef.current.focus(); +    } +  }, [userInputRef]);    useEffect(() => {      if (isHovered) { @@ -134,6 +143,7 @@ function StepContainer(props: StepContainerProps) {            {props.historyNode.step.name === "Waiting for user input" && (              <input +              ref={userInputRef}                className="m-auto p-2 rounded-md border-1 border-solid text-white w-3/4 border-gray-200 bg-vsc-background"                onKeyDown={(e) => {                  if (e.key === "Enter") { @@ -144,6 +154,9 @@ function StepContainer(props: StepContainerProps) {                onSubmit={(ev) => {                  props.onUserInput(ev.currentTarget.value);                }} +              onClick={(e) => { +                e.stopPropagation(); +              }}              />            )}            {props.historyNode.step.name === "Waiting for user confirmation" && ( @@ -165,24 +178,6 @@ function StepContainer(props: StepContainerProps) {                />              </>            )} - -          {open && ( -            <> -              {/* {props.historyNode.observation && ( -                <SubContainer title="Error"> -                  <CodeBlock>Error Here</CodeBlock> -                </SubContainer> -              )} */} -              {/* {props.iterationContext.suggestedChanges.map((sc) => { -              return ( -                <SubContainer title="Suggested Change"> -                  {sc.filepath} -                  <CodeBlock>{sc.replacement}</CodeBlock> -                </SubContainer> -              ); -            })} */} -            </> -          )}          </StepContainerDiv>        </GradientBorder> diff --git a/extension/react-app/src/components/index.ts b/extension/react-app/src/components/index.ts index e37c97f3..7ba60467 100644 --- a/extension/react-app/src/components/index.ts +++ b/extension/react-app/src/components/index.ts @@ -45,7 +45,7 @@ export const Pre = styled.pre`    border-radius: ${defaultBorderRadius};    padding: 8px;    max-height: 150px; -  overflow: scroll; +  overflow-y: scroll;    margin: 0;    background-color: ${secondaryDark};    border: none; diff --git a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts new file mode 100644 index 00000000..18a91de7 --- /dev/null +++ b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts @@ -0,0 +1,13 @@ +abstract class AbstractContinueGUIClientProtocol { +  abstract sendMainInput(input: string): void; + +  abstract reverseToIndex(index: number): void; + +  abstract sendRefinementInput(input: string, index: number): void; + +  abstract sendStepUserInput(input: string, index: number): void; + +  abstract onStateUpdate(state: any): void; +} + +export default AbstractContinueGUIClientProtocol; diff --git a/extension/react-app/src/hooks/messenger.ts b/extension/react-app/src/hooks/messenger.ts new file mode 100644 index 00000000..e2a0bab8 --- /dev/null +++ b/extension/react-app/src/hooks/messenger.ts @@ -0,0 +1,108 @@ +// console.log("Websocket import"); +// const WebSocket = require("ws"); + +export abstract class Messenger { +  abstract send(messageType: string, data: object): void; + +  abstract onMessageType( +    messageType: string, +    callback: (data: object) => void +  ): void; + +  abstract onMessage(callback: (messageType: string, data: any) => void): void; + +  abstract onOpen(callback: () => void): void; + +  abstract onClose(callback: () => void): void; + +  abstract sendAndReceive(messageType: string, data: any): Promise<any>; +} + +export class WebsocketMessenger extends Messenger { +  websocket: WebSocket; +  private onMessageListeners: { +    [messageType: string]: ((data: object) => void)[]; +  } = {}; +  private onOpenListeners: (() => void)[] = []; +  private onCloseListeners: (() => void)[] = []; +  private serverUrl: string; + +  _newWebsocket(): WebSocket { +    // // Dynamic import, because WebSocket is builtin with browser, but not with node. And can't use require in browser. +    // if (typeof process === "object") { +    //   console.log("Using node"); +    //   // process is only available in Node +    //   var WebSocket = require("ws"); +    // } + +    const newWebsocket = new WebSocket(this.serverUrl); +    for (const listener of this.onOpenListeners) { +      this.onOpen(listener); +    } +    for (const listener of this.onCloseListeners) { +      this.onClose(listener); +    } +    for (const messageType in this.onMessageListeners) { +      for (const listener of this.onMessageListeners[messageType]) { +        this.onMessageType(messageType, listener); +      } +    } +    return newWebsocket; +  } + +  constructor(serverUrl: string) { +    super(); +    this.serverUrl = serverUrl; +    this.websocket = this._newWebsocket(); +  } + +  send(messageType: string, data: object) { +    const payload = JSON.stringify({ messageType, data }); +    if (this.websocket.readyState === this.websocket.OPEN) { +      this.websocket.send(payload); +    } else { +      if (this.websocket.readyState !== this.websocket.CONNECTING) { +        this.websocket = this._newWebsocket(); +      } +      this.websocket.addEventListener("open", () => { +        this.websocket.send(payload); +      }); +    } +  } + +  sendAndReceive(messageType: string, data: any): Promise<any> { +    return new Promise((resolve, reject) => { +      const eventListener = (data: any) => { +        // THIS ISN"T GETTING CALLED +        resolve(data); +        this.websocket.removeEventListener("message", eventListener); +      }; +      this.onMessageType(messageType, eventListener); +      this.send(messageType, data); +    }); +  } + +  onMessageType(messageType: string, callback: (data: any) => void): void { +    this.websocket.addEventListener("message", (event: any) => { +      const msg = JSON.parse(event.data); +      if (msg.messageType === messageType) { +        callback(msg.data); +      } +    }); +  } + +  onMessage(callback: (messageType: string, data: any) => void): void { +    this.websocket.addEventListener("message", (event) => { +      const msg = JSON.parse(event.data); +      callback(msg.messageType, msg.data); +    }); +  } + +  onOpen(callback: () => void): void { +    this.websocket.addEventListener("open", callback); +  } + +  onClose(callback: () => void): void { +    this.websocket.addEventListener("close", callback); +  } +} diff --git a/extension/react-app/src/hooks/useContinueGUIProtocol.ts b/extension/react-app/src/hooks/useContinueGUIProtocol.ts new file mode 100644 index 00000000..a3a1d0c9 --- /dev/null +++ b/extension/react-app/src/hooks/useContinueGUIProtocol.ts @@ -0,0 +1,49 @@ +import AbstractContinueGUIClientProtocol from "./ContinueGUIClientProtocol"; +// import { Messenger, WebsocketMessenger } from "../../../src/util/messenger"; +import { Messenger, WebsocketMessenger } from "./messenger"; +import { VscodeMessenger } from "./vscodeMessenger"; + +class ContinueGUIClientProtocol extends AbstractContinueGUIClientProtocol { +  messenger: Messenger; +  // Server URL must contain the session ID param +  serverUrlWithSessionId: string; + +  constructor( +    serverUrlWithSessionId: string, +    useVscodeMessagePassing: boolean +  ) { +    super(); +    this.serverUrlWithSessionId = serverUrlWithSessionId; +    if (useVscodeMessagePassing) { +      this.messenger = new VscodeMessenger(serverUrlWithSessionId); +    } else { +      this.messenger = new WebsocketMessenger(serverUrlWithSessionId); +    } +  } + +  sendMainInput(input: string) { +    this.messenger.send("main_input", { input }); +  } + +  reverseToIndex(index: number) { +    this.messenger.send("reverse_to_index", { index }); +  } + +  sendRefinementInput(input: string, index: number) { +    this.messenger.send("refinement_input", { input, index }); +  } + +  sendStepUserInput(input: string, index: number) { +    this.messenger.send("step_user_input", { input, index }); +  } + +  onStateUpdate(callback: (state: any) => void) { +    this.messenger.onMessageType("state_update", (data: any) => { +      if (data.state) { +        callback(data.state); +      } +    }); +  } +} + +export default ContinueGUIClientProtocol; diff --git a/extension/react-app/src/hooks/useWebsocket.ts b/extension/react-app/src/hooks/useWebsocket.ts index 147172bd..e762666f 100644 --- a/extension/react-app/src/hooks/useWebsocket.ts +++ b/extension/react-app/src/hooks/useWebsocket.ts @@ -1,67 +1,39 @@  import React, { useEffect, useState } from "react";  import { RootStore } from "../redux/store";  import { useSelector } from "react-redux"; +import ContinueGUIClientProtocol from "./useContinueGUIProtocol"; +import { postVscMessage } from "../vscode"; -function useContinueWebsocket( -  serverUrl: string, -  onMessage: (message: { data: any }) => void -) { +function useContinueGUIProtocol(useVscodeMessagePassing: boolean = true) {    const sessionId = useSelector((state: RootStore) => state.config.sessionId); -  const [websocket, setWebsocket] = useState<WebSocket | undefined>(undefined); +  const serverHttpUrl = useSelector((state: RootStore) => state.config.apiUrl); +  const [client, setClient] = useState<ContinueGUIClientProtocol | undefined>( +    undefined +  ); -  async function connect() { -    while (!sessionId) { -      await new Promise((resolve) => setTimeout(resolve, 300)); +  useEffect(() => { +    if (!sessionId || !serverHttpUrl) { +      if (useVscodeMessagePassing) { +        postVscMessage("onLoad", {}); +      } +      setClient(undefined); +      return;      } -    console.log("Creating websocket", sessionId); - -    const wsUrl = -      serverUrl.replace("http", "ws") + -      "/notebook/ws?session_id=" + +    const serverUrlWithSessionId = +      serverHttpUrl.replace("http", "ws") + +      "/gui/ws?session_id=" +        encodeURIComponent(sessionId); -    const ws = new WebSocket(wsUrl); -    setWebsocket(ws); - -    // Set up callbacks -    ws.onopen = () => { -      console.log("Websocket opened"); -      ws.send(JSON.stringify({ sessionId })); -    }; - -    ws.onmessage = (msg) => { -      onMessage(msg); -      console.log("Got message", msg); -    }; - -    ws.onclose = (msg) => { -      console.log("Websocket closed"); -      setWebsocket(undefined); -    }; - -    return ws; -  } - -  async function getConnection() { -    if (!websocket) { -      return await connect(); -    } -    return websocket; -  } - -  async function send(message: object) { -    let ws = await getConnection(); -    ws.send(JSON.stringify(message)); -  } - -  useEffect(() => { -    if (!sessionId) { -      return; -    } -    connect(); -  }, [sessionId]); +    console.log("Creating websocket", serverUrlWithSessionId); +    console.log("Using vscode message passing", useVscodeMessagePassing); +    const newClient = new ContinueGUIClientProtocol( +      serverUrlWithSessionId, +      useVscodeMessagePassing +    ); +    setClient(newClient); +  }, [sessionId, serverHttpUrl]); -  return { send }; +  return client;  } -export default useContinueWebsocket; +export default useContinueGUIProtocol; diff --git a/extension/react-app/src/hooks/vscodeMessenger.ts b/extension/react-app/src/hooks/vscodeMessenger.ts new file mode 100644 index 00000000..ba19586b --- /dev/null +++ b/extension/react-app/src/hooks/vscodeMessenger.ts @@ -0,0 +1,71 @@ +import { postVscMessage } from "../vscode"; +// import { Messenger } from "../../../src/util/messenger"; +import { Messenger } from "./messenger"; + +export class VscodeMessenger extends Messenger { +  serverUrl: string; + +  constructor(serverUrl: string) { +    super(); +    this.serverUrl = serverUrl; +    postVscMessage("websocketForwardingOpen", { url: this.serverUrl }); +  } + +  send(messageType: string, data: object) { +    postVscMessage("websocketForwardingMessage", { +      message: { messageType, data }, +      url: this.serverUrl, +    }); +  } + +  onMessageType(messageType: string, callback: (data: object) => void): void { +    window.addEventListener("message", (event: any) => { +      if (event.data.type === "websocketForwardingMessage") { +        const data = JSON.parse(event.data.data); +        if (data.messageType === messageType) { +          callback(data.data); +        } +      } +    }); +  } + +  onMessage(callback: (messageType: string, data: any) => void): void { +    window.addEventListener("message", (event: any) => { +      if (event.data.type === "websocketForwardingMessage") { +        const data = JSON.parse(event.data.data); +        callback(data.messageType, data.data); +      } +    }); +  } + +  sendAndReceive(messageType: string, data: any): Promise<any> { +    return new Promise((resolve) => { +      const handler = (event: any) => { +        if (event.data.type === "websocketForwardingMessage") { +          const data = JSON.parse(event.data.data); +          if (data.messageType === messageType) { +            window.removeEventListener("message", handler); +            resolve(data.data); +          } +        } +      }; +      window.addEventListener("message", handler); +      this.send(messageType, data); +    }); +  } + +  onOpen(callback: () => void): void { +    window.addEventListener("message", (event: any) => { +      if (event.data.type === "websocketForwardingOpen") { +        callback(); +      } +    }); +  } +  onClose(callback: () => void): void { +    window.addEventListener("message", (event: any) => { +      if (event.data.type === "websocketForwardingClose") { +        callback(); +      } +    }); +  } +} diff --git a/extension/react-app/src/index.css b/extension/react-app/src/index.css index dd38eec3..20599d30 100644 --- a/extension/react-app/src/index.css +++ b/extension/react-app/src/index.css @@ -21,7 +21,7 @@  html,  body,  #root { -  height: calc(100% - 7px); +  height: calc(100%);  }  body { diff --git a/extension/react-app/src/main.tsx b/extension/react-app/src/main.tsx index 791f139e..1b94dc82 100644 --- a/extension/react-app/src/main.tsx +++ b/extension/react-app/src/main.tsx @@ -1,10 +1,19 @@ -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App' -import './index.css' +import React from "react"; +import ReactDOM from "react-dom/client"; +import App from "./App"; +import "./index.css"; -ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( +import posthog from "posthog-js"; +import { PostHogProvider } from "posthog-js/react"; + +posthog.init("phc_JS6XFROuNbhJtVCEdTSYk6gl5ArRrTNMpCcguAXlSPs", { +  api_host: "https://app.posthog.com", +}); + +ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(    <React.StrictMode> -    <App /> -  </React.StrictMode>, -) +    <PostHogProvider client={posthog}> +      <App /> +    </PostHogProvider> +  </React.StrictMode> +); diff --git a/extension/react-app/src/tabs/chat/MessageDiv.tsx b/extension/react-app/src/tabs/chat/MessageDiv.tsx index d7c79721..9bdd8638 100644 --- a/extension/react-app/src/tabs/chat/MessageDiv.tsx +++ b/extension/react-app/src/tabs/chat/MessageDiv.tsx @@ -20,7 +20,8 @@ const Container = styled.div`    margin: 3px;    width: fit-content;    max-width: 75%; -  overflow: scroll; +  overflow-y: scroll; +  scrollbar-gutter: stable both-edges;    word-wrap: break-word;    -ms-word-wrap: break-word;    height: fit-content; diff --git a/extension/react-app/src/tabs/notebook.tsx b/extension/react-app/src/tabs/gui.tsx index a9c69c5b..42ad4ed5 100644 --- a/extension/react-app/src/tabs/notebook.tsx +++ b/extension/react-app/src/tabs/gui.tsx @@ -14,10 +14,12 @@ import StepContainer from "../components/StepContainer";  import { useSelector } from "react-redux";  import { RootStore } from "../redux/store";  import useContinueWebsocket from "../hooks/useWebsocket"; +import useContinueGUIProtocol from "../hooks/useWebsocket"; -let TopNotebookDiv = styled.div` +let TopGUIDiv = styled.div`    display: grid;    grid-template-columns: 1fr; +  overflow: scroll;  `;  let UserInputQueueItem = styled.div` @@ -28,17 +30,15 @@ let UserInputQueueItem = styled.div`    text-align: center;  `; -interface NotebookProps { +interface GUIProps {    firstObservation?: any;  } -function Notebook(props: NotebookProps) { -  const serverUrl = useSelector((state: RootStore) => state.config.apiUrl); - +function GUI(props: GUIProps) {    const [waitingForSteps, setWaitingForSteps] = useState(false);    const [userInputQueue, setUserInputQueue] = useState<string[]>([]);    const [history, setHistory] = useState<History | undefined>(); -  //   { +  // {    //   timeline: [    //     {    //       step: { @@ -154,33 +154,19 @@ function Notebook(props: NotebookProps) {    //     },    //   ],    //   current_index: 0, -  // } as any -  // ); +  // } as any); -  const { send: websocketSend } = useContinueWebsocket(serverUrl, (msg) => { -    let data = JSON.parse(msg.data); -    if (data.messageType === "state") { -      setWaitingForSteps(data.state.active); -      setHistory(data.state.history); -      setUserInputQueue(data.state.user_input_queue); -    } -  }); +  const client = useContinueGUIProtocol(); -  // useEffect(() => { -  //   (async () => { -  //     if (sessionId && props.firstObservation) { -  //       let resp = await fetch(serverUrl + "/observation", { -  //         method: "POST", -  //         headers: new Headers({ -  //           "x-continue-session-id": sessionId, -  //         }), -  //         body: JSON.stringify({ -  //           observation: props.firstObservation, -  //         }), -  //       }); -  //     } -  //   })(); -  // }, [props.firstObservation]); +  useEffect(() => { +    console.log("CLIENT ON STATE UPDATE: ", client, client?.onStateUpdate); +    client?.onStateUpdate((state) => { +      console.log("Received state update: ", state); +      setWaitingForSteps(state.active); +      setHistory(state.history); +      setUserInputQueue(state.user_input_queue); +    }); +  }, [client]);    const mainTextInputRef = useRef<HTMLTextAreaElement>(null); @@ -201,14 +187,12 @@ function Notebook(props: NotebookProps) {    const onMainTextInput = () => {      if (mainTextInputRef.current) { -      let value = mainTextInputRef.current.value; +      if (!client) return; +      let input = mainTextInputRef.current.value;        setWaitingForSteps(true); -      websocketSend({ -        messageType: "main_input", -        value: value, -      }); +      client.sendMainInput(input);        setUserInputQueue((queue) => { -        return [...queue, value]; +        return [...queue, input];        });        mainTextInputRef.current.value = "";        mainTextInputRef.current.style.height = ""; @@ -216,17 +200,22 @@ function Notebook(props: NotebookProps) {    };    const onStepUserInput = (input: string, index: number) => { +    if (!client) return;      console.log("Sending step user input", input, index); -    websocketSend({ -      messageType: "step_user_input", -      value: input, -      index, -    }); +    client.sendStepUserInput(input, index);    };    // const iterations = useSelector(selectIterations);    return ( -    <TopNotebookDiv> +    <TopGUIDiv> +      {typeof client === "undefined" && ( +        <> +          <Loader></Loader> +          <p style={{ textAlign: "center" }}> +            Trying to reconnect with server... +          </p> +        </> +      )}        {history?.timeline.map((node: HistoryNode, index: number) => {          return (            <StepContainer @@ -237,17 +226,10 @@ function Notebook(props: NotebookProps) {              inFuture={index > history?.current_index}              historyNode={node}              onRefinement={(input: string) => { -              websocketSend({ -                messageType: "refinement_input", -                value: input, -                index, -              }); +              client?.sendRefinementInput(input, index);              }}              onReverse={() => { -              websocketSend({ -                messageType: "reverse", -                index, -              }); +              client?.reverseToIndex(index);              }}            />          ); @@ -278,8 +260,8 @@ function Notebook(props: NotebookProps) {          }}        ></MainTextInput>        <ContinueButton onClick={onMainTextInput}></ContinueButton> -    </TopNotebookDiv> +    </TopGUIDiv>    );  } -export default Notebook; +export default GUI; diff --git a/extension/react-app/src/vscode/index.ts b/extension/react-app/src/vscode/index.ts index 7e373cd9..0785aa4d 100644 --- a/extension/react-app/src/vscode/index.ts +++ b/extension/react-app/src/vscode/index.ts @@ -5,6 +5,7 @@ declare const vscode: any;  export function postVscMessage(type: string, data: any) {    if (typeof vscode === "undefined") { +    console.log("Unable to send message: vscode is undefined");      return;    }    vscode.postMessage({ | 
