Skip to content

Commit

Permalink
Fix: Keypresses in Terminal throws exception (All-Hands-AI#71)
Browse files Browse the repository at this point in the history
  • Loading branch information
yimothysu committed Mar 21, 2024
1 parent 0380070 commit a722f5c
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 15 deletions.
1 change: 1 addition & 0 deletions frontend/.eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
{
"files": ["*.ts", "*.tsx"],
"rules": {
"no-underscore-dangle": "off",
"jsx-a11y/no-static-element-interactions": "off",
"jsx-a11y/click-events-have-key-events": "off",
"react/no-array-index-key": "off"
Expand Down
9 changes: 0 additions & 9 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
"vite": "^5.1.6",
"vite-tsconfig-paths": "^4.3.2",
"web-vitals": "^2.1.4",
"xterm-addon-attach": "^0.9.0",
"xterm-addon-fit": "^0.8.0"
},
"scripts": {
Expand Down
41 changes: 36 additions & 5 deletions frontend/src/components/Terminal.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,39 @@
import React, { useEffect, useRef } from "react";
import { Terminal as XtermTerminal } from "@xterm/xterm";
import { AttachAddon } from "xterm-addon-attach";
import { IDisposable, Terminal as XtermTerminal } from "@xterm/xterm";
import { FitAddon } from "xterm-addon-fit";
import "@xterm/xterm/css/xterm.css";

class JsonWebsocketAddon {
_socket: WebSocket;

_disposables: IDisposable[];

constructor(socket: WebSocket) {
this._socket = socket;
this._disposables = [];
}

activate(terminal: XtermTerminal) {
this._disposables.push(
terminal.onData((data) => {
const payload = JSON.stringify({ action: "terminal", data });
this._socket.send(payload);
}),
);
this._socket.addEventListener("message", (event) => {
const { message } = JSON.parse(event.data);
if (message.action === "terminal") {
terminal.write(message.data);
}
});
}

dispose() {
this._disposables.forEach((d) => d.dispose());
this._socket.removeEventListener("message", () => {});
}
}

function Terminal(): JSX.Element {
const terminalRef = useRef<HTMLDivElement>(null);
const WS_URL = import.meta.env.VITE_TERMINAL_WS_URL;
Expand Down Expand Up @@ -32,11 +62,12 @@ function Terminal(): JSX.Element {

if (!WS_URL) {
throw new Error(
"The environment variable REACT_APP_TERMINAL_WS_URL is not set. Please set it to the WebSocket URL of the terminal server.",
"The environment variable VITE_TERMINAL_WS_URL is not set. Please set it to the WebSocket URL of the terminal server.",
);
}
const attachAddon = new AttachAddon(new WebSocket(WS_URL as string));
terminal.loadAddon(attachAddon);
const socket = new WebSocket(WS_URL as string);
const jsonWebsocketAddon = new JsonWebsocketAddon(socket);
terminal.loadAddon(jsonWebsocketAddon);

return () => {
terminal.dispose();
Expand Down
6 changes: 6 additions & 0 deletions server/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ async def websocket_endpoint(websocket: WebSocket):
continue

agent_listener = asyncio.create_task(listen_for_agent_messages())
if action == "terminal":
msg = {
"action": "terminal",
"data": data["data"]
}
await send_message_to_client(get_message_payload(msg))
else:
if agent_websocket is None:
await send_message_to_client(get_error_payload("Agent not connected"))
Expand Down

0 comments on commit a722f5c

Please sign in to comment.