Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor of error handling #4575

Open
wants to merge 67 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
1dd8c3f
prevent evenstream from looping back on itself
rbren Oct 26, 2024
ba3c558
use hasattr
rbren Oct 26, 2024
1b72a89
refactor a bit
rbren Oct 26, 2024
ed3d944
revert perms
rbren Oct 26, 2024
57662b6
private method
rbren Oct 26, 2024
a7ce34e
async_add_event
rbren Oct 26, 2024
d8becc2
remove unnecessary return
rbren Oct 26, 2024
d9811b0
stop dropping events while pending_action is set
rbren Oct 26, 2024
47a95f7
remove FatalErrorObservation
rbren Oct 26, 2024
d46b712
refactor react_to_error a bit more
rbren Oct 26, 2024
f9c283e
fix comments
rbren Oct 26, 2024
1c44fa6
fix test
rbren Oct 26, 2024
3f67ed3
fix test
rbren Oct 26, 2024
cdb8066
Merge branch 'main' of github.com:All-Hands-AI/OpenHands into rb/prev…
enyst Oct 27, 2024
6aff381
Update openhands/controller/state/state.py
enyst Oct 27, 2024
f67c8d5
fix conflicts - merge branch 'main' of github.com:All-Hands-AI/OpenHa…
enyst Oct 29, 2024
b278d45
more invisible conflicts
enyst Oct 29, 2024
d19f998
remove fatal observations
rbren Oct 29, 2024
4745cb6
more refactoring
rbren Oct 29, 2024
d7fe86d
new react_to_exception
rbren Oct 29, 2024
d240775
change up status message plumbing
rbren Oct 29, 2024
d9f834e
logspam
rbren Oct 29, 2024
99486f4
fix await
rbren Oct 29, 2024
ed7f4ee
better error toasts on frontend
rbren Oct 29, 2024
2e342b8
better error plumbing
rbren Oct 29, 2024
154b838
logspam
rbren Oct 29, 2024
45ba7cf
better restarting
rbren Oct 29, 2024
9c28805
Update openhands/controller/agent_controller.py
enyst Oct 30, 2024
b757831
Update openhands/controller/agent_controller.py
enyst Oct 30, 2024
b8c9f10
Merge branches 'rb/prevent-event-loop' and 'rb/prevent-event-loop' of…
rbren Oct 30, 2024
3e446bb
delint
rbren Oct 30, 2024
9289cdb
fix threading
rbren Oct 30, 2024
194188d
Merge branch 'main' into rb/prevent-event-loop
rbren Oct 30, 2024
52bbdd8
fix async
rbren Oct 30, 2024
e78af12
add id for auth errors
rbren Oct 30, 2024
7b7b306
better error messages\, use messages instead of toast
rbren Oct 30, 2024
baf2c11
no more retrys
rbren Oct 30, 2024
4be71e1
fix no headline
rbren Oct 30, 2024
3e07a2d
fix call
rbren Oct 30, 2024
c6fd5ac
runtime errors plumbing through properly
rbren Oct 30, 2024
0012ed4
logspam
rbren Oct 30, 2024
a81975f
remove another retry
rbren Oct 30, 2024
7798896
refactor remote runtime error handling
rbren Oct 31, 2024
c5369d8
more refactoring
rbren Oct 31, 2024
b72239f
minor fixes
rbren Oct 31, 2024
b8f221f
fix session init
rbren Oct 31, 2024
2993051
add fixme
rbren Oct 31, 2024
43eb0d3
fix lint
rbren Oct 31, 2024
1002d44
change test name
rbren Oct 31, 2024
4f69d38
lint
rbren Oct 31, 2024
5efc862
fix tests
rbren Oct 31, 2024
75d8028
fix some tests
rbren Oct 31, 2024
fa25ad1
better names
rbren Oct 31, 2024
0a5e900
fix message
rbren Oct 31, 2024
019aed6
fix more tests
rbren Oct 31, 2024
f66e7f1
Merge branch 'main' into rb/prevent-event-loop
rbren Oct 31, 2024
58f3db6
Merge branch 'main' into rb/prevent-event-loop
rbren Oct 31, 2024
0793e9f
remove redundant 200 checks
rbren Oct 31, 2024
a021dad
fix tests
rbren Oct 31, 2024
7d4e3fb
Merge branch 'main' into rb/prevent-event-loop
rbren Oct 31, 2024
a08879f
add stacklevel
rbren Oct 31, 2024
98e25d1
add debug info
rbren Oct 31, 2024
0e87415
fix timeout error
rbren Oct 31, 2024
6cc2cac
Revert "add debug info"
rbren Oct 31, 2024
4f84a50
add ids to ErrorObservation
rbren Oct 31, 2024
88a0eb4
add some error_ids
rbren Oct 31, 2024
2128d0b
fix type error
rbren Oct 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion evaluation/EDA/run_infer.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ def process_instance(
metadata=metadata,
history=histories,
metrics=metrics,
error=state.last_error if state and state.last_error else None,
error=state.get_last_error() if state and state.get_last_error() else None,
test_result={
'success': test_result,
'final_message': final_message,
Expand Down
2 changes: 1 addition & 1 deletion evaluation/agent_bench/run_infer.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ def process_instance(
metadata=metadata,
history=histories,
metrics=metrics,
error=state.last_error if state and state.last_error else None,
error=state.get_last_error() if state and state.get_last_error() else None,
test_result={
'agent_answer': agent_answer,
'final_answer': final_ans,
Expand Down
2 changes: 1 addition & 1 deletion evaluation/aider_bench/run_infer.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ def process_instance(
metadata=metadata,
history=histories,
metrics=metrics,
error=state.last_error if state and state.last_error else None,
error=state.get_last_error() if state and state.get_last_error() else None,
test_result=test_result,
)
return output
Expand Down
2 changes: 1 addition & 1 deletion evaluation/biocoder/run_infer.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ def process_instance(
metadata=metadata,
history=histories,
metrics=metrics,
error=state.last_error if state and state.last_error else None,
error=state.get_last_error() if state and state.get_last_error() else None,
test_result=test_result,
)
return output
Expand Down
2 changes: 1 addition & 1 deletion evaluation/bird/run_infer.py
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ def execute_sql(db_path, sql):
metadata=metadata,
history=histories,
metrics=metrics,
error=state.last_error if state and state.last_error else None,
error=state.get_last_error() if state and state.get_last_error() else None,
test_result=test_result,
)
return output
Expand Down
2 changes: 1 addition & 1 deletion evaluation/browsing_delegation/run_infer.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def process_instance(
metadata=metadata,
history=histories,
metrics=metrics,
error=state.last_error if state and state.last_error else None,
error=state.get_last_error() if state and state.get_last_error() else None,
test_result={
'query': instance.instruction,
'action': last_delegate_action,
Expand Down
2 changes: 1 addition & 1 deletion evaluation/gaia/run_infer.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ def process_instance(
metadata=metadata,
history=histories,
metrics=metrics,
error=state.last_error if state and state.last_error else None,
error=state.get_last_error() if state and state.get_last_error() else None,
test_result=test_result,
)
return output
Expand Down
2 changes: 1 addition & 1 deletion evaluation/gorilla/run_infer.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def process_instance(
metadata=metadata,
history=histories,
metrics=metrics,
error=state.last_error if state and state.last_error else None,
error=state.get_last_error() if state and state.get_last_error() else None,
test_result={
'text': model_answer_raw,
'correct': correct,
Expand Down
2 changes: 1 addition & 1 deletion evaluation/gpqa/run_infer.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ def process_instance(
metadata=metadata,
history=state.history.compatibility_for_eval_history_pairs(),
metrics=metrics,
error=state.last_error if state and state.last_error else None,
error=state.get_last_error() if state and state.get_last_error() else None,
test_result={
'result': test_result,
'found_answers': found_answers,
Expand Down
2 changes: 1 addition & 1 deletion evaluation/humanevalfix/run_infer.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ def process_instance(
metadata=metadata,
history=histories,
metrics=metrics,
error=state.last_error if state and state.last_error else None,
error=state.get_last_error() if state and state.get_last_error() else None,
test_result=test_result,
)
return output
Expand Down
2 changes: 1 addition & 1 deletion evaluation/integration_tests/run_infer.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ def process_instance(
metadata=metadata,
history=histories,
metrics=metrics,
error=state.last_error if state and state.last_error else None,
error=state.get_last_error() if state and state.get_last_error() else None,
test_result=test_result.model_dump(),
)
return output
Expand Down
2 changes: 1 addition & 1 deletion evaluation/logic_reasoning/run_infer.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ def process_instance(
metadata=metadata,
history=histories,
metrics=metrics,
error=state.last_error if state and state.last_error else None,
error=state.get_last_error() if state and state.get_last_error() else None,
test_result=test_result,
)
return output
Expand Down
2 changes: 1 addition & 1 deletion evaluation/miniwob/run_infer.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ def process_instance(
metadata=metadata,
history=histories,
metrics=metrics,
error=state.last_error if state and state.last_error else None,
error=state.get_last_error() if state and state.get_last_error() else None,
test_result={
'reward': reward,
},
Expand Down
2 changes: 1 addition & 1 deletion evaluation/mint/run_infer.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ def process_instance(
metadata=metadata,
history=histories,
metrics=metrics,
error=state.last_error if state and state.last_error else None,
error=state.get_last_error() if state and state.get_last_error() else None,
test_result={
'success': task_state.success if task_state else False,
},
Expand Down
8 changes: 4 additions & 4 deletions evaluation/swe_bench/run_infer.py
Original file line number Diff line number Diff line change
Expand Up @@ -409,11 +409,11 @@ def process_instance(

# if fatal error, throw EvalError to trigger re-run
if (
state.last_error
and 'fatal error during agent execution' in state.last_error
state.get_last_error()
and 'fatal error during agent execution' in state.get_last_error()
and 'stuck in a loop' not in state.last_error
):
raise EvalException('Fatal error detected: ' + state.last_error)
raise EvalException('Fatal error detected: ' + state.get_last_error())

# ======= THIS IS SWE-Bench specific =======
# Get git patch
Expand Down Expand Up @@ -450,7 +450,7 @@ def process_instance(
metadata=metadata,
history=histories,
metrics=metrics,
error=state.last_error if state and state.last_error else None,
error=state.get_last_error() if state and state.get_last_error() else None,
)
return output

Expand Down
2 changes: 1 addition & 1 deletion evaluation/toolqa/run_infer.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def process_instance(instance: Any, metadata: EvalMetadata, reset_logger: bool =
metadata=metadata,
history=histories,
metrics=metrics,
error=state.last_error if state and state.last_error else None,
error=state.get_last_error() if state and state.get_last_error() else None,
)
return output

Expand Down
2 changes: 1 addition & 1 deletion evaluation/webarena/run_infer.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ def process_instance(
metadata=metadata,
history=histories,
metrics=metrics,
error=state.last_error if state and state.last_error else None,
error=state.get_last_error() if state and state.get_last_error() else None,
test_result={
'reward': reward,
},
Expand Down
4 changes: 2 additions & 2 deletions frontend/__tests__/components/chat/chat-interface.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,14 +128,14 @@ describe.skip("ChatInterface", () => {
timestamp: new Date().toISOString(),
},
{
error: "Woops!",
error: true,
id: "",
message: "Something went wrong",
},
];
renderChatInterface(messages);

const error = screen.getByTestId("error-message");
expect(within(error).getByText("Woops!")).toBeInTheDocument();
expect(within(error).getByText("Something went wrong")).toBeInTheDocument();
});

Expand Down
27 changes: 20 additions & 7 deletions frontend/src/components/AgentStatusBar.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { useSelector } from "react-redux";
import toast from "react-hot-toast";
import { I18nKey } from "#/i18n/declaration";
import { RootState } from "#/store";
import AgentState from "#/types/AgentState";
Expand All @@ -16,7 +17,7 @@ enum IndicatorColor {
}

function AgentStatusBar() {
const { t } = useTranslation();
const { t, i18n } = useTranslation();
const { curAgentState } = useSelector((state: RootState) => state.agent);
const { curStatusMessage } = useSelector((state: RootState) => state.status);

Expand Down Expand Up @@ -94,15 +95,27 @@ function AgentStatusBar() {
const [statusMessage, setStatusMessage] = React.useState<string>("");

React.useEffect(() => {
if (curAgentState === AgentState.LOADING) {
const trimmedCustomMessage = curStatusMessage.status.trim();
if (trimmedCustomMessage) {
setStatusMessage(t(trimmedCustomMessage));
return;
let message = curStatusMessage.message || "";
if (curStatusMessage?.id) {
const id = curStatusMessage.id.trim();
if (i18n.exists(id)) {
message = t(curStatusMessage.id.trim()) || message;
}
}
if (curStatusMessage?.type === "error") {
toast.error(message);
return;
}
if (curAgentState === AgentState.LOADING && message.trim()) {
setStatusMessage(message);
} else {
setStatusMessage(AgentStatusMap[curAgentState].message);
}
}, [curStatusMessage.id]);

React.useEffect(() => {
setStatusMessage(AgentStatusMap[curAgentState].message);
}, [curAgentState, curStatusMessage.status]);
}, [curAgentState]);

return (
<div className="flex flex-col items-center">
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/chat-interface.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export function ChatInterface() {
isErrorMessage(message) ? (
<ErrorMessage
key={index}
error={message.error}
id={message.id}
message={message.message}
/>
) : (
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/components/chat/message.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ type Message = {
};

type ErrorMessage = {
error: string;
error: boolean;
id?: string;
message: string;
};
35 changes: 31 additions & 4 deletions frontend/src/components/error-message.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,41 @@
import { useState, useEffect } from "react";
import { useTranslation } from "react-i18next";

interface ErrorMessageProps {
error: string;
id?: string;
message: string;
}

export function ErrorMessage({ error, message }: ErrorMessageProps) {
export function ErrorMessage({ id, message }: ErrorMessageProps) {
const { t, i18n } = useTranslation();
const [showDetails, setShowDetails] = useState(true);
const [headline, setHeadline] = useState("");
const [details, setDetails] = useState(message);

useEffect(() => {
if (id && i18n.exists(id)) {
setHeadline(t(id));
setDetails(message);
setShowDetails(false);
}
}, [id, message, i18n.language]);

return (
<div className="flex gap-2 items-center justify-start border-l-2 border-danger pl-2 my-2 py-2">
<div className="text-sm leading-4 flex flex-col gap-2">
<p className="text-danger font-bold">{error}</p>
<p className="text-neutral-300">{message}</p>
{headline && <p className="text-danger font-bold">{headline}</p>}
{headline && (
<button
type="button"
onClick={() => setShowDetails(!showDetails)}
className="cursor-pointer text-left"
>
{showDetails
? t("ERROR_MESSAGE$HIDE_DETAILS")
: t("ERROR_MESSAGE$SHOW_DETAILS")}
</button>
)}
{showDetails && <p className="text-neutral-300">{details}</p>}
</div>
</div>
);
Expand Down
18 changes: 18 additions & 0 deletions frontend/src/i18n/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1441,6 +1441,12 @@
"fr": "Privé",
"tr": "Özel"
},
"ERROR_MESSAGE$SHOW_DETAILS": {
"en": "Show details"
},
"ERROR_MESSAGE$HIDE_DETAILS": {
"en": "Hide details"
},
"STATUS$STARTING_RUNTIME": {
"en": "Starting Runtime...",
"zh-CN": "启动运行时...",
Expand Down Expand Up @@ -1510,5 +1516,17 @@
"ar": "في انتظار جاهزية العميل...",
"fr": "En attente que le client soit prêt...",
"tr": "İstemcinin hazır olması bekleniyor..."
},
"STATUS$ERROR_LLM_AUTHENTICATION": {
"en": "Error authenticating with the LLM provider. Please check your API key"
},
"STATUS$ERROR_RUNTIME_DISCONNECTED": {
"en": "There was an error while connecting to the runtime. Please refresh the page."
},
"AGENT_ERROR$BAD_ACTION": {
"en": "Agent tried to execute a malformed action."
},
"AGENT_ERROR$ACTION_TIMEOUT": {
"en": "Action timed out."
}
}
22 changes: 6 additions & 16 deletions frontend/src/routes/_oh.app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
const data = await retrieveLatestGitHubCommit(ghToken, repo);
if (isGitHubErrorReponse(data)) {
// TODO: Handle error
console.error("Failed to retrieve latest commit", data);

Check warning on line 102 in frontend/src/routes/_oh.app.tsx

View workflow job for this annotation

GitHub Actions / Lint frontend

Unexpected console statement
} else {
[lastCommit] = data;
}
Expand Down Expand Up @@ -185,21 +185,6 @@
if (q) addIntialQueryToChat(q, files);
}, [settings]);

const handleError = (message: string) => {
const [error, ...rest] = message.split(":");
const details = rest.join(":");
if (!details) {
dispatch(
addErrorMessage({
error: "An error has occured",
message: error,
}),
);
} else {
dispatch(addErrorMessage({ error, message: details }));
}
};

const handleMessage = React.useCallback(
(message: MessageEvent<WebSocket.Data>) => {
// set token received from the server
Expand All @@ -225,7 +210,12 @@
return;
}
if (isErrorObservation(parsed)) {
handleError(parsed.message);
dispatch(
addErrorMessage({
id: parsed.extras?.error_id,
message: parsed.message,
}),
);
return;
}

Expand Down
Loading