Skip to content

Commit 93a98ea

Browse files
committed
feat: add inline model error card with settings CTA in chat flow
Show model errors (invalid API key, model not found, quota exceeded) as an inline warning card in the chat message list instead of only a toast. The card includes a contextual description and an "Open Model Settings" button that navigates to /setting/models.
1 parent f1f1bcc commit 93a98ea

15 files changed

Lines changed: 110 additions & 12 deletions

File tree

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
14+
15+
import { Button } from '@/components/ui/button';
16+
import { TriangleAlert } from 'lucide-react';
17+
import { useTranslation } from 'react-i18next';
18+
import { useNavigate } from 'react-router-dom';
19+
20+
interface ModelErrorCardProps {
21+
content: string;
22+
errorCode?: string | null;
23+
}
24+
25+
export function ModelErrorCard({ content, errorCode }: ModelErrorCardProps) {
26+
const { t } = useTranslation();
27+
const navigate = useNavigate();
28+
29+
const description = (() => {
30+
let text: string;
31+
switch (errorCode) {
32+
case 'invalid_api_key':
33+
text = t('chat.model-error-invalid-api-key');
34+
break;
35+
case 'model_not_found':
36+
text = t('chat.model-error-model-not-found');
37+
break;
38+
case 'insufficient_quota':
39+
text = t('chat.model-error-quota-exceeded');
40+
break;
41+
default:
42+
return content;
43+
}
44+
// The i18n strings end with " in" for the toast's inline link.
45+
// Strip it here since the card uses a separate button.
46+
return text.replace(/ in$/, '');
47+
})();
48+
49+
return (
50+
<div className="flex w-full items-start gap-2 rounded-xl bg-surface-warning p-4">
51+
<TriangleAlert size={16} className="text-icon-warning" />
52+
<div className="flex flex-col items-start gap-2">
53+
<p className="mt-0 font-inter text-sm font-medium text-text-warning">
54+
{description}
55+
</p>
56+
<Button
57+
variant="outline"
58+
size="sm"
59+
className="w-fit"
60+
onClick={() => navigate('/setting/models')}
61+
>
62+
{t('chat.model-error-open-settings')}
63+
</Button>
64+
</div>
65+
</div>
66+
);
67+
}

src/components/ChatBox/UserQueryGroup.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import React, {
2323
useSyncExternalStore,
2424
} from 'react';
2525
import { AgentMessageCard } from './MessageItem/AgentMessageCard';
26+
import { ModelErrorCard } from './MessageItem/ModelErrorCard';
2627
import { NoticeCard } from './MessageItem/NoticeCard';
2728
import { UserMessageCard } from './MessageItem/UserMessageCard';
2829
import { StreamingTaskList } from './TaskBox/StreamingTaskList';
@@ -287,6 +288,22 @@ export const UserQueryGroup: React.FC<UserQueryGroupProps> = ({
287288

288289
{/* Other Messages */}
289290
{queryGroup.otherMessages.map((message) => {
291+
if (message.error_code) {
292+
return (
293+
<motion.div
294+
key={`error-${message.id}`}
295+
initial={{ opacity: 0, y: 10 }}
296+
animate={{ opacity: 1, y: 0 }}
297+
transition={{ delay: 0.2 }}
298+
className="mt-2 flex flex-col gap-4 px-sm"
299+
>
300+
<ModelErrorCard
301+
content={message.content}
302+
errorCode={message.error_code}
303+
/>
304+
</motion.div>
305+
);
306+
}
290307
if (message.content.length > 0) {
291308
if (message.step === AgentStep.END) {
292309
return (

src/i18n/locales/ar/chat.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,6 @@
5656
"model-error-go-to-settings": "Model Settings",
5757
"model-error-invalid-api-key": "Your API key is invalid or expired. Please update it in",
5858
"model-error-model-not-found": "The configured model was not found. Please check your settings in",
59-
"model-error-quota-exceeded": "You've exceeded your API quota. Please check your plan or update your key in"
59+
"model-error-quota-exceeded": "You've exceeded your API quota. Please check your plan or update your key in",
60+
"model-error-open-settings": "Open Model Settings"
6061
}

src/i18n/locales/de/chat.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,6 @@
5656
"model-error-go-to-settings": "Model Settings",
5757
"model-error-invalid-api-key": "Your API key is invalid or expired. Please update it in",
5858
"model-error-model-not-found": "The configured model was not found. Please check your settings in",
59-
"model-error-quota-exceeded": "You've exceeded your API quota. Please check your plan or update your key in"
59+
"model-error-quota-exceeded": "You've exceeded your API quota. Please check your plan or update your key in",
60+
"model-error-open-settings": "Open Model Settings"
6061
}

src/i18n/locales/en-us/chat.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,6 @@
5656
"model-error-go-to-settings": "Model Settings",
5757
"model-error-invalid-api-key": "Your API key is invalid or expired. Please update it in",
5858
"model-error-model-not-found": "The configured model was not found. Please check your settings in",
59-
"model-error-quota-exceeded": "You've exceeded your API quota. Please check your plan or update your key in"
59+
"model-error-quota-exceeded": "You've exceeded your API quota. Please check your plan or update your key in",
60+
"model-error-open-settings": "Open Model Settings"
6061
}

src/i18n/locales/es/chat.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,6 @@
5656
"model-error-go-to-settings": "Model Settings",
5757
"model-error-invalid-api-key": "Your API key is invalid or expired. Please update it in",
5858
"model-error-model-not-found": "The configured model was not found. Please check your settings in",
59-
"model-error-quota-exceeded": "You've exceeded your API quota. Please check your plan or update your key in"
59+
"model-error-quota-exceeded": "You've exceeded your API quota. Please check your plan or update your key in",
60+
"model-error-open-settings": "Open Model Settings"
6061
}

src/i18n/locales/fr/chat.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,6 @@
5656
"model-error-go-to-settings": "Model Settings",
5757
"model-error-invalid-api-key": "Your API key is invalid or expired. Please update it in",
5858
"model-error-model-not-found": "The configured model was not found. Please check your settings in",
59-
"model-error-quota-exceeded": "You've exceeded your API quota. Please check your plan or update your key in"
59+
"model-error-quota-exceeded": "You've exceeded your API quota. Please check your plan or update your key in",
60+
"model-error-open-settings": "Open Model Settings"
6061
}

src/i18n/locales/it/chat.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,6 @@
5656
"model-error-go-to-settings": "Model Settings",
5757
"model-error-invalid-api-key": "Your API key is invalid or expired. Please update it in",
5858
"model-error-model-not-found": "The configured model was not found. Please check your settings in",
59-
"model-error-quota-exceeded": "You've exceeded your API quota. Please check your plan or update your key in"
59+
"model-error-quota-exceeded": "You've exceeded your API quota. Please check your plan or update your key in",
60+
"model-error-open-settings": "Open Model Settings"
6061
}

src/i18n/locales/ja/chat.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,6 @@
5656
"model-error-go-to-settings": "Model Settings",
5757
"model-error-invalid-api-key": "Your API key is invalid or expired. Please update it in",
5858
"model-error-model-not-found": "The configured model was not found. Please check your settings in",
59-
"model-error-quota-exceeded": "You've exceeded your API quota. Please check your plan or update your key in"
59+
"model-error-quota-exceeded": "You've exceeded your API quota. Please check your plan or update your key in",
60+
"model-error-open-settings": "Open Model Settings"
6061
}

src/i18n/locales/ko/chat.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,6 @@
5656
"model-error-go-to-settings": "Model Settings",
5757
"model-error-invalid-api-key": "Your API key is invalid or expired. Please update it in",
5858
"model-error-model-not-found": "The configured model was not found. Please check your settings in",
59-
"model-error-quota-exceeded": "You've exceeded your API quota. Please check your plan or update your key in"
59+
"model-error-quota-exceeded": "You've exceeded your API quota. Please check your plan or update your key in",
60+
"model-error-open-settings": "Open Model Settings"
6061
}

0 commit comments

Comments
 (0)