Skip to content

Commit

Permalink
Merge
Browse files Browse the repository at this point in the history
  • Loading branch information
SmartManoj committed Nov 14, 2024
2 parents 8695b26 + 8dee334 commit f2ed6b8
Show file tree
Hide file tree
Showing 44 changed files with 898 additions and 121 deletions.
2 changes: 1 addition & 1 deletion evaluation/swe_bench/run_infer.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@
from openhands.events.observation import CmdOutputObservation, ErrorObservation
from openhands.events.serialization.event import event_to_dict
from openhands.runtime.base import Runtime
from openhands.runtime.utils.shutdown_listener import sleep_if_should_continue
from openhands.utils.async_utils import call_async_from_sync
from openhands.utils.shutdown_listener import sleep_if_should_continue

check_if_resolved()
USE_HINT_TEXT = os.environ.get('USE_HINT_TEXT', 'false').lower() == 'true'
Expand Down
8 changes: 4 additions & 4 deletions frontend/package-lock.json

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

4 changes: 2 additions & 2 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"isbot": "^5.1.17",
"jose": "^5.9.4",
"monaco-editor": "^0.52.0",
"posthog-js": "^1.176.0",
"posthog-js": "^1.184.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-highlight": "^0.15.0",
Expand Down Expand Up @@ -120,4 +120,4 @@
"public"
]
}
}
}
5 changes: 3 additions & 2 deletions frontend/public/config.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"APP_MODE": "oss",
"GITHUB_CLIENT_ID": ""
}
"GITHUB_CLIENT_ID": "",
"POSTHOG_CLIENT_KEY": "phc_3ESMmY9SgqEAGBB6sMGK5ayYHkeUuknH2vP6FmWH9RA"
}
9 changes: 9 additions & 0 deletions frontend/src/api/open-hands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
GitHubAccessTokenResponse,
ErrorResponse,
GetConfigResponse,
GetVSCodeUrlResponse,
} from "./open-hands.types";

class OpenHands {
Expand Down Expand Up @@ -174,6 +175,14 @@ class OpenHands {
true,
);
}

/**
* Get the VSCode URL
* @returns VSCode URL
*/
static async getVSCodeUrl(): Promise<GetVSCodeUrlResponse> {
return request(`/api/vscode-url`, {}, false, false, 1);
}
}

export default OpenHands;
8 changes: 7 additions & 1 deletion frontend/src/api/open-hands.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,11 @@ export interface Feedback {

export interface GetConfigResponse {
APP_MODE: "saas" | "oss";
GITHUB_CLIENT_ID: string | null;
GITHUB_CLIENT_ID: string;
POSTHOG_CLIENT_KEY: string;
}

export interface GetVSCodeUrlResponse {
vscode_url: string | null;
error?: string;
}
57 changes: 57 additions & 0 deletions frontend/src/assets/vscode-alt.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 0 additions & 3 deletions frontend/src/components/event-handler.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
} from "#/context/ws-client-provider";
import { ErrorObservation } from "#/types/core/observations";
import { addErrorMessage, addUserMessage } from "#/state/chatSlice";
import { handleAssistantMessage } from "#/services/actions";
import {
getCloneRepoCommand,
getGitHubTokenCommand,
Expand Down Expand Up @@ -112,9 +111,7 @@ export function EventHandler({ children }: React.PropsWithChildren) {
message: event.message,
}),
);
return;
}
handleAssistantMessage(event);
}, [events.length]);

React.useEffect(() => {
Expand Down
56 changes: 54 additions & 2 deletions frontend/src/components/file-explorer/FileExplorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { useTranslation } from "react-i18next";
import { twMerge } from "tailwind-merge";
import AgentState from "#/types/AgentState";
import { setRefreshID } from "#/state/codeSlice";
import { addAssistantMessage } from "#/state/chatSlice";
import IconButton from "../IconButton";
import ExplorerTree from "./ExplorerTree";
import toast from "#/utils/toast";
Expand All @@ -20,6 +21,7 @@ import { I18nKey } from "#/i18n/declaration";
import OpenHands from "#/api/open-hands";
import { useFiles } from "#/context/files";
import { isOpenHandsErrorResponse } from "#/api/open-hands.utils";
import VSCodeIcon from "#/assets/vscode-alt.svg?react";

interface ExplorerActionsProps {
onRefresh: () => void;
Expand Down Expand Up @@ -168,6 +170,35 @@ function FileExplorer({ error, isOpen, onToggle }: FileExplorerProps) {
}
};

const handleVSCodeClick = async (e: React.MouseEvent) => {
e.preventDefault();
try {
const response = await OpenHands.getVSCodeUrl();
if (response.vscode_url) {
dispatch(
addAssistantMessage(
"You opened VS Code. Please inform the agent of any changes you made to the workspace or environment. To avoid conflicts, it's best to pause the agent before making any changes.",
),
);
window.open(response.vscode_url, "_blank");
} else {
toast.error(
`open-vscode-error-${new Date().getTime()}`,
t(I18nKey.EXPLORER$VSCODE_SWITCHING_ERROR_MESSAGE, {
error: response.error,
}),
);
}
} catch (exp_error) {
toast.error(
`open-vscode-error-${new Date().getTime()}`,
t(I18nKey.EXPLORER$VSCODE_SWITCHING_ERROR_MESSAGE, {
error: String(exp_error),
}),
);
}
};

React.useEffect(() => {
refreshWorkspace();
}, [curAgentState]);
Expand Down Expand Up @@ -210,7 +241,7 @@ function FileExplorer({ error, isOpen, onToggle }: FileExplorerProps) {
!isOpen ? "w-12" : "w-60",
)}
>
<div className="flex flex-col relative h-full px-3 py-2">
<div className="flex flex-col relative h-full px-3 py-2 overflow-hidden">
<div className="sticky top-0 bg-neutral-800">
<div
className={twMerge(
Expand All @@ -232,7 +263,7 @@ function FileExplorer({ error, isOpen, onToggle }: FileExplorerProps) {
</div>
</div>
{!error && (
<div className="overflow-auto flex-grow">
<div className="overflow-auto flex-grow min-h-0">
<div style={{ display: !isOpen ? "none" : "block" }}>
<ExplorerTree files={paths} />
</div>
Expand All @@ -243,6 +274,27 @@ function FileExplorer({ error, isOpen, onToggle }: FileExplorerProps) {
<p className="text-neutral-300 text-sm">{error}</p>
</div>
)}
{isOpen && (
<button
type="button"
onClick={handleVSCodeClick}
disabled={
curAgentState === AgentState.INIT ||
curAgentState === AgentState.LOADING
}
className={twMerge(
"mt-auto mb-2 w-full h-10 text-white rounded flex items-center justify-center gap-2 transition-colors",
curAgentState === AgentState.INIT ||
curAgentState === AgentState.LOADING
? "bg-neutral-600 cursor-not-allowed"
: "bg-[#4465DB] hover:bg-[#3451C7]",
)}
aria-label="Open in VS Code"
>
<VSCodeIcon width={20} height={20} />
Open in VS Code
</button>
)}
</div>
<input
data-testid="file-input"
Expand Down
33 changes: 27 additions & 6 deletions frontend/src/context/ws-client-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { Settings } from "#/services/settings";
import ActionType from "#/types/ActionType";
import EventLogger from "#/utils/event-logger";
import AgentState from "#/types/AgentState";
import { handleAssistantMessage } from "#/services/actions";

const RECONNECT_RETRIES = 5;

export enum WsClientProviderStatus {
STOPPED,
Expand Down Expand Up @@ -46,6 +49,7 @@ export function WsClientProvider({
const closeRef = React.useRef<ReturnType<typeof setTimeout> | null>(null);
const [status, setStatus] = React.useState(WsClientProviderStatus.STOPPED);
const [events, setEvents] = React.useState<Record<string, unknown>[]>([]);
const [retryCount, setRetryCount] = React.useState(RECONNECT_RETRIES);

function send(event: Record<string, unknown>) {
if (!wsRef.current) {
Expand All @@ -56,6 +60,7 @@ export function WsClientProvider({
}

function handleOpen() {
setRetryCount(RECONNECT_RETRIES);
setStatus(WsClientProviderStatus.OPENING);
const initEvent = {
action: ActionType.INIT,
Expand All @@ -76,11 +81,19 @@ export function WsClientProvider({
) {
setStatus(WsClientProviderStatus.ERROR);
}

handleAssistantMessage(event);
}

function handleClose() {
setStatus(WsClientProviderStatus.STOPPED);
setEvents([]);
if (retryCount) {
setTimeout(() => {
setRetryCount(retryCount - 1);
}, 1000);
} else {
setStatus(WsClientProviderStatus.STOPPED);
setEvents([]);
}
wsRef.current = null;
}

Expand All @@ -95,7 +108,7 @@ export function WsClientProvider({
let ws = wsRef.current;

// If disabled close any existing websockets...
if (!enabled) {
if (!enabled || !retryCount) {
if (ws) {
ws.close();
}
Expand All @@ -116,7 +129,11 @@ export function WsClientProvider({
const baseUrl =
import.meta.env.VITE_BACKEND_BASE_URL || window?.location.host;
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
ws = new WebSocket(`${protocol}//${baseUrl}/ws`, [
let wsUrl = `${protocol}//${baseUrl}/ws`;
if (events.length) {
wsUrl += `?latest_event_id=${events[events.length - 1].id}`;
}
ws = new WebSocket(wsUrl, [
"openhands",
token || "NO_JWT",
ghToken || "NO_GITHUB",
Expand All @@ -136,7 +153,7 @@ export function WsClientProvider({
ws.removeEventListener("error", handleError);
ws.removeEventListener("close", handleClose);
};
}, [enabled, token, ghToken]);
}, [enabled, token, ghToken, retryCount]);

// Strict mode mounts and unmounts each component twice, so we have to wait in the destructor
// before actually closing the socket and cancel the operation if the component gets remounted.
Expand All @@ -148,7 +165,11 @@ export function WsClientProvider({

return () => {
closeRef.current = setTimeout(() => {
wsRef.current?.close();
const ws = wsRef.current;
if (ws) {
ws.removeEventListener("close", handleClose);
ws.close();
}
}, 100);
};
}, []);
Expand Down
17 changes: 14 additions & 3 deletions frontend/src/entry.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,26 @@ import { Provider } from "react-redux";
import posthog from "posthog-js";
import "./i18n";
import store from "./store";
import OpenHands from "./api/open-hands";

function PosthogInit() {
const [key, setKey] = React.useState<string | null>(null);

React.useEffect(() => {
posthog.init("phc_3ESMmY9SgqEAGBB6sMGK5ayYHkeUuknH2vP6FmWH9RA", {
api_host: "https://us.i.posthog.com",
person_profiles: "identified_only",
OpenHands.getConfig().then((config) => {
setKey(config.POSTHOG_CLIENT_KEY);
});
}, []);

React.useEffect(() => {
if (key) {
posthog.init(key, {
api_host: "https://us.i.posthog.com",
person_profiles: "identified_only",
});
}
}, [key]);

return null;
}

Expand Down
Loading

0 comments on commit f2ed6b8

Please sign in to comment.