mirror of
https://github.com/OpenHands/OpenHands.git
synced 2025-12-26 05:48:36 +08:00
Feat out of credits msg (#6969)
Co-authored-by: openhands <openhands@all-hands.dev>
This commit is contained in:
parent
f437d06e81
commit
be73792230
@ -2,6 +2,7 @@ import { render, screen } from "@testing-library/react";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { Messages } from "#/components/features/chat/messages";
|
||||
import type { Message } from "#/message";
|
||||
import { renderWithProviders } from "test-utils";
|
||||
|
||||
describe("File Operations Messages", () => {
|
||||
it("should show success indicator for successful file read operation", () => {
|
||||
@ -16,7 +17,7 @@ describe("File Operations Messages", () => {
|
||||
},
|
||||
];
|
||||
|
||||
render(<Messages messages={messages} isAwaitingUserConfirmation={false} />);
|
||||
renderWithProviders(<Messages messages={messages} isAwaitingUserConfirmation={false} />);
|
||||
|
||||
const statusIcon = screen.getByTestId("status-icon");
|
||||
expect(statusIcon).toBeInTheDocument();
|
||||
@ -35,7 +36,7 @@ describe("File Operations Messages", () => {
|
||||
},
|
||||
];
|
||||
|
||||
render(<Messages messages={messages} isAwaitingUserConfirmation={false} />);
|
||||
renderWithProviders(<Messages messages={messages} isAwaitingUserConfirmation={false} />);
|
||||
|
||||
const statusIcon = screen.getByTestId("status-icon");
|
||||
expect(statusIcon).toBeInTheDocument();
|
||||
@ -54,7 +55,7 @@ describe("File Operations Messages", () => {
|
||||
},
|
||||
];
|
||||
|
||||
render(<Messages messages={messages} isAwaitingUserConfirmation={false} />);
|
||||
renderWithProviders(<Messages messages={messages} isAwaitingUserConfirmation={false} />);
|
||||
|
||||
const statusIcon = screen.getByTestId("status-icon");
|
||||
expect(statusIcon).toBeInTheDocument();
|
||||
@ -73,7 +74,7 @@ describe("File Operations Messages", () => {
|
||||
},
|
||||
];
|
||||
|
||||
render(<Messages messages={messages} isAwaitingUserConfirmation={false} />);
|
||||
renderWithProviders(<Messages messages={messages} isAwaitingUserConfirmation={false} />);
|
||||
|
||||
const statusIcon = screen.getByTestId("status-icon");
|
||||
expect(statusIcon).toBeInTheDocument();
|
||||
|
||||
@ -2,6 +2,7 @@ import { useState, useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import Markdown from "react-markdown";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import { Link } from "react-router";
|
||||
import { code } from "../markdown/code";
|
||||
import { ol, ul } from "../markdown/list";
|
||||
import ArrowUp from "#/icons/angle-up-solid.svg?react";
|
||||
@ -9,6 +10,8 @@ import ArrowDown from "#/icons/angle-down-solid.svg?react";
|
||||
import CheckCircle from "#/icons/check-circle-solid.svg?react";
|
||||
import XCircle from "#/icons/x-circle-solid.svg?react";
|
||||
import { cn } from "#/utils/utils";
|
||||
import { useConfig } from "#/hooks/query/use-config";
|
||||
import { BILLING_SETTINGS } from "#/utils/feature-flags";
|
||||
|
||||
interface ExpandableMessageProps {
|
||||
id?: string;
|
||||
@ -23,6 +26,7 @@ export function ExpandableMessage({
|
||||
type,
|
||||
success,
|
||||
}: ExpandableMessageProps) {
|
||||
const { data: config } = useConfig();
|
||||
const { t, i18n } = useTranslation();
|
||||
const [showDetails, setShowDetails] = useState(true);
|
||||
const [headline, setHeadline] = useState("");
|
||||
@ -38,6 +42,28 @@ export function ExpandableMessage({
|
||||
|
||||
const statusIconClasses = "h-4 w-4 ml-2 inline";
|
||||
|
||||
if (
|
||||
BILLING_SETTINGS() &&
|
||||
config?.APP_MODE === "saas" &&
|
||||
id === "STATUS$ERROR_LLM_OUT_OF_CREDITS"
|
||||
) {
|
||||
return (
|
||||
<div className="flex gap-2 items-center justify-start border-l-2 pl-2 my-2 py-2 border-danger">
|
||||
<div className="text-sm w-full">
|
||||
<div className="font-bold text-danger">
|
||||
{t("STATUS$ERROR_LLM_OUT_OF_CREDITS")}
|
||||
</div>
|
||||
<Link
|
||||
className="mt-2 mb-2 w-full h-10 rounded flex items-center justify-center gap-2 bg-primary text-[#0D0F11]"
|
||||
to="/settings/billing"
|
||||
>
|
||||
{t("BILLING$CLICK_TO_TOP_UP")}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
|
||||
@ -3833,7 +3833,21 @@
|
||||
"pt": "Ocorreu um erro ao conectar ao ambiente de execução. Por favor, atualize a página.",
|
||||
"tr": "Çalışma zamanına bağlanırken bir hata oluştu. Lütfen sayfayı yenileyin."
|
||||
},
|
||||
|
||||
"STATUS$ERROR_LLM_OUT_OF_CREDITS": {
|
||||
"en": "You're out of OpenHands Credits",
|
||||
"ja": "OpenHandsクレジットが不足しています",
|
||||
"zh-CN": "您的OpenHands点数已用完",
|
||||
"zh-TW": "您的OpenHands點數已用完",
|
||||
"ko-KR": "OpenHands 크레딧이 소진되었습니다",
|
||||
"no": "Du er tom for OpenHands-kreditter",
|
||||
"it": "Hai esaurito i crediti OpenHands",
|
||||
"pt": "Você está sem créditos OpenHands",
|
||||
"es": "Te has quedado sin créditos de OpenHands",
|
||||
"ar": "لقد نفدت رصيدك من OpenHands",
|
||||
"fr": "Vous n'avez plus de crédits OpenHands",
|
||||
"tr": "OpenHands kredileriniz tükendi",
|
||||
"de": "Ihre OpenHands-Guthaben sind aufgebraucht"
|
||||
},
|
||||
"STATUS$ERROR_RUNTIME_DISCONNECTED": {
|
||||
"en": "There was an error while connecting to the runtime. Please refresh the page.",
|
||||
"zh-CN": "运行时已断开连接",
|
||||
@ -4558,5 +4572,20 @@
|
||||
"SETTINGS_FORM$ENABLE_DEFAULT_CONDENSER_SWITCH_LABEL": {
|
||||
"en": "Enable Memory Condenser",
|
||||
"zh-TW": "啟用記憶體壓縮器"
|
||||
},
|
||||
"BILLING$CLICK_TO_TOP_UP": {
|
||||
"en": "Add funds to Your Account",
|
||||
"ja": "アカウントに資金を追加",
|
||||
"zh-CN": "为您的账户充值",
|
||||
"zh-TW": "為您的帳戶充值",
|
||||
"ko-KR": "계정에 자금 추가",
|
||||
"no": "Legg til midler på kontoen din",
|
||||
"it": "Aggiungi fondi al tuo account",
|
||||
"pt": "Adicionar fundos à sua conta",
|
||||
"es": "Añadir fondos a tu cuenta",
|
||||
"ar": "إضافة رصيد إلى حسابك",
|
||||
"fr": "Ajouter des fonds à votre compte",
|
||||
"tr": "Hesabınıza bakiye ekleyin",
|
||||
"de": "Guthaben zu Ihrem Konto hinzufügen"
|
||||
}
|
||||
}
|
||||
|
||||
@ -227,6 +227,8 @@ class AgentController:
|
||||
err_id = 'STATUS$ERROR_LLM_SERVICE_UNAVAILABLE'
|
||||
elif isinstance(e, litellm.InternalServerError):
|
||||
err_id = 'STATUS$ERROR_LLM_INTERNAL_SERVER_ERROR'
|
||||
elif isinstance(e, litellm.BadRequestError) and 'ExceededBudget' in str(e):
|
||||
err_id = 'STATUS$ERROR_LLM_OUT_OF_CREDITS'
|
||||
elif isinstance(e, RateLimitError):
|
||||
await self.set_agent_state_to(AgentState.RATE_LIMITED)
|
||||
return
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user