mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-27 21:08:00 +00:00
fix(chat): show specific error messages instead of generic 'Something went wrong' (#1566)
Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai>
This commit is contained in:
co-authored by
Steven Enamakel
parent
6d2e722fa8
commit
156a016279
@@ -809,7 +809,7 @@ const ChatRuntimeProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
finishChatDoneTurn(event, 'ordinary');
|
||||
},
|
||||
onError: event => {
|
||||
const eventKey = `error:${event.thread_id}:${event.request_id ?? 'none'}:${event.error_type}:${event.message}`;
|
||||
const eventKey = `error:${event.thread_id}:${event.request_id ?? 'none'}:${event.error_type}`;
|
||||
if (
|
||||
!markChatEventSeen(eventKey, { threadId: event.thread_id, requestId: event.request_id })
|
||||
)
|
||||
@@ -840,14 +840,17 @@ const ChatRuntimeProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
const currentState = store.getState();
|
||||
const threadMessages = currentState.thread.messagesByThreadId[event.thread_id] ?? [];
|
||||
const lastMsg = threadMessages[threadMessages.length - 1];
|
||||
if (
|
||||
!(lastMsg?.sender === 'agent' && lastMsg?.content === USER_FACING_AGENT_ERROR_MESSAGE)
|
||||
) {
|
||||
// For the generic 'inference' type the server may send a raw internal error string;
|
||||
// use the safe user-facing constant instead. For all other classified types
|
||||
// (rate_limited, timeout, auth_error, etc.) the message comes from
|
||||
// classify_inference_error() in web.rs and is already user-friendly.
|
||||
const errorContent =
|
||||
event.error_type === 'inference'
|
||||
? USER_FACING_AGENT_ERROR_MESSAGE
|
||||
: event.message || USER_FACING_AGENT_ERROR_MESSAGE;
|
||||
if (!(lastMsg?.sender === 'agent' && lastMsg?.content === errorContent)) {
|
||||
void dispatch(
|
||||
addInferenceResponse({
|
||||
content: USER_FACING_AGENT_ERROR_MESSAGE,
|
||||
threadId: event.thread_id,
|
||||
})
|
||||
addInferenceResponse({ content: errorContent, threadId: event.thread_id })
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -90,7 +90,18 @@ export interface ChatErrorEvent {
|
||||
thread_id: string;
|
||||
request_id?: string;
|
||||
message: string;
|
||||
error_type: 'network' | 'timeout' | 'tool_error' | 'inference' | 'cancelled';
|
||||
error_type:
|
||||
| 'network'
|
||||
| 'timeout'
|
||||
| 'tool_error'
|
||||
| 'inference'
|
||||
| 'cancelled'
|
||||
| 'rate_limited'
|
||||
| 'auth_error'
|
||||
| 'provider_error'
|
||||
| 'context_overflow'
|
||||
| 'model_unavailable'
|
||||
| 'budget_exhausted';
|
||||
round: number | null;
|
||||
}
|
||||
|
||||
|
||||
@@ -130,6 +130,62 @@ fn generic_inference_error_user_message() -> &'static str {
|
||||
"Something went wrong. Please try again.\nThis error has been reported. You can also report it on Discord.\n<openhuman-link path=\"community/discord\">Report on Discord</openhuman-link>"
|
||||
}
|
||||
|
||||
fn classify_inference_error(err: &str) -> (&'static str, &'static str) {
|
||||
let lower = err.to_lowercase();
|
||||
if lower.contains("rate limit") || lower.contains("429") {
|
||||
(
|
||||
"rate_limited",
|
||||
"You're being rate-limited. Please wait a moment and try again.",
|
||||
)
|
||||
} else if lower.contains("timeout") || lower.contains("timed out") {
|
||||
(
|
||||
"timeout",
|
||||
"The request timed out. Please check your connection and try again.",
|
||||
)
|
||||
} else if lower.contains("401") || lower.contains("unauthorized") || lower.contains("api key") {
|
||||
(
|
||||
"auth_error",
|
||||
"There's an authentication issue with the AI provider. Please check your API key in settings.",
|
||||
)
|
||||
} else if lower.contains("402")
|
||||
|| lower.contains("payment required")
|
||||
|| lower.contains("insufficient balance")
|
||||
{
|
||||
(
|
||||
"budget_exhausted",
|
||||
"Insufficient credits. Please top up to continue.",
|
||||
)
|
||||
} else if lower.contains("500")
|
||||
|| lower.contains("internal server")
|
||||
|| lower.contains("service unavailable")
|
||||
|| lower.contains("503")
|
||||
{
|
||||
(
|
||||
"provider_error",
|
||||
"The AI provider is temporarily unavailable. Please try again later.",
|
||||
)
|
||||
} else if lower.contains("context")
|
||||
&& (lower.contains("length")
|
||||
|| lower.contains("limit")
|
||||
|| lower.contains("exceed")
|
||||
|| lower.contains("token"))
|
||||
{
|
||||
(
|
||||
"context_overflow",
|
||||
"The conversation is too long. Please start a new chat.",
|
||||
)
|
||||
} else if lower.contains("model")
|
||||
&& (lower.contains("not found") || lower.contains("unavailable"))
|
||||
{
|
||||
(
|
||||
"model_unavailable",
|
||||
"The selected model is not available. Please check your model settings.",
|
||||
)
|
||||
} else {
|
||||
("inference", generic_inference_error_user_message())
|
||||
}
|
||||
}
|
||||
|
||||
fn prompt_guard_user_message(action: PromptEnforcementAction) -> &'static str {
|
||||
match action {
|
||||
PromptEnforcementAction::Allow => "Message accepted.",
|
||||
@@ -280,13 +336,14 @@ pub async fn start_chat(
|
||||
"run_chat_task failed client_id={} thread_id={} request_id={} error={}",
|
||||
client_id_task, thread_id_task, request_id_task, err
|
||||
);
|
||||
let (classified_type, classified_message) = classify_inference_error(&err);
|
||||
crate::core::observability::report_error(
|
||||
detailed.as_str(),
|
||||
"web_channel",
|
||||
"run_chat_task",
|
||||
&[
|
||||
("channel", "web"),
|
||||
("error_type", "inference"),
|
||||
("error_type", classified_type),
|
||||
("thread_id", thread_id_task.as_str()),
|
||||
("request_id", request_id_task.as_str()),
|
||||
],
|
||||
@@ -297,8 +354,8 @@ pub async fn start_chat(
|
||||
thread_id: thread_id_task.clone(),
|
||||
request_id: request_id_task.clone(),
|
||||
full_response: None,
|
||||
message: Some(generic_inference_error_user_message().to_string()),
|
||||
error_type: Some("inference".to_string()),
|
||||
message: Some(classified_message.to_string()),
|
||||
error_type: Some(classified_type.to_string()),
|
||||
tool_name: None,
|
||||
skill_id: None,
|
||||
args: None,
|
||||
|
||||
Reference in New Issue
Block a user