Skip to content

Commit 8cca868

Browse files
mirror29claude
andcommitted
fix(dashboard): 全局打开 LLM 配置并补齐翻译
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent b53294f commit 8cca868

8 files changed

Lines changed: 164 additions & 81 deletions

File tree

apps/dashboard/messages/en.json

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,42 @@
409409
"none": "",
410410
"truncated": "Showing the latest {n} — earlier ones aren't listed here."
411411
},
412+
"llm": {
413+
"title": "LLM Settings",
414+
"loading": "Loading…",
415+
"loadFailed": "Could not load settings: {error}",
416+
"noConfigs": "No configuration yet. Add an API key to start.",
417+
"active": "Active",
418+
"model": "Model: {model}",
419+
"defaultModel": "default",
420+
"key": "Key: {key}",
421+
"delete": "Delete",
422+
"provider": "Provider",
423+
"customEndpoint": "Custom endpoint URL",
424+
"customName": "Custom name",
425+
"customNamePlaceholder": "My provider",
426+
"customProvider": "Custom endpoint",
427+
"modelOptional": "Model (optional)",
428+
"modelPlaceholder": "Leave blank to use the default",
429+
"apiKey": "API Key *",
430+
"saving": "Saving…",
431+
"save": "Save",
432+
"cancel": "Cancel",
433+
"addConfig": "Add configuration",
434+
"saveFailed": "Could not save configuration",
435+
"saveMissingId": "Could not save configuration: no configuration ID returned",
436+
"saveActivationFailed": "Configuration was saved, but could not be activated",
437+
"saved": "Configuration saved",
438+
"activated": "Configuration activated",
439+
"activationFailed": "Could not activate configuration",
440+
"deleted": "Configuration deleted",
441+
"deleteFailed": "Could not delete configuration",
442+
"confirmDelete": "Delete configuration?",
443+
"deleteDescription": "Delete the configuration for {provider}? This cannot be undone.",
444+
"deleting": "Deleting…",
445+
"sidebarEntry": "LLM Settings",
446+
"invalidKey": "The active LLM API key is invalid or temporarily unavailable. Check the configuration and retry."
447+
},
412448
"chat": {
413449
"title": "Agent",
414450
"online": "online",

apps/dashboard/messages/zh.json

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,42 @@
409409
"none": "",
410410
"truncated": "仅显示最近 {n} 条 —— 更早的未在此列出。"
411411
},
412+
"llm": {
413+
"title": "LLM 配置",
414+
"loading": "加载中…",
415+
"loadFailed": "加载失败:{error}",
416+
"noConfigs": "暂无配置,请添加 API Key",
417+
"active": "当前",
418+
"model": "模型:{model}",
419+
"defaultModel": "默认",
420+
"key": "密钥:{key}",
421+
"delete": "删除",
422+
"provider": "供应商",
423+
"customEndpoint": "自定义端点 URL",
424+
"customName": "自定义名称",
425+
"customNamePlaceholder": "我的供应商",
426+
"customProvider": "自定义端点",
427+
"modelOptional": "模型(可选)",
428+
"modelPlaceholder": "留空使用默认",
429+
"apiKey": "API Key *",
430+
"saving": "保存中…",
431+
"save": "保存",
432+
"cancel": "取消",
433+
"addConfig": "新增配置",
434+
"saveFailed": "保存失败",
435+
"saveMissingId": "保存失败:未返回配置 ID",
436+
"saveActivationFailed": "配置已保存,但激活失败",
437+
"saved": "配置已保存",
438+
"activated": "已切换配置",
439+
"activationFailed": "切换失败",
440+
"deleted": "配置已删除",
441+
"deleteFailed": "删除失败",
442+
"confirmDelete": "确认删除",
443+
"deleteDescription": "确定要删除配置 {provider} 吗?此操作无法撤销。",
444+
"deleting": "删除中…",
445+
"sidebarEntry": "LLM 配置",
446+
"invalidKey": "当前 LLM API Key 无效或暂时不可用,请检查配置后重试"
447+
},
412448
"chat": {
413449
"title": "Agent",
414450
"online": "在线",

apps/dashboard/src/app/[locale]/layout.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { notFound } from "next/navigation";
44

55
import { ActivityFooter } from "@/components/activity/ActivityFooter";
66
import { ConsoleChat } from "@/components/chat/ConsoleChat";
7+
import { LLMConfigGate } from "@/components/llm/LLMConfigGate";
78
import { ConsoleSidebar } from "@/components/shell/ConsoleSidebar";
89
import { Toaster } from "@/components/ui/sonner";
910
import { routing } from "@/i18n/routing";
@@ -42,6 +43,7 @@ export default async function LocaleLayout({
4243
</main>
4344
{/* 内嵌 agent 对话栏 —— 常驻 layout,切面切换不丢对话(见 ConsoleChat)。 */}
4445
<ConsoleChat />
46+
<LLMConfigGate />
4547
{/* 常驻底部活动日志(终端风)—— 随时可回溯 agent 跨模块活动(见 ActivityFooter)。 */}
4648
<ActivityFooter />
4749
</div>

apps/dashboard/src/components/chat/ChatThread.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export function ChatThread({
5959
onSwitchThread: (id: string) => void;
6060
}) {
6161
const t = useTranslations("chat");
62+
const tLlm = useTranslations("llm");
6263

6364
const hook = useCopilotChatInternal();
6465
const messages = (hook.messages ?? []) as unknown as AGMessage[];
@@ -91,14 +92,14 @@ export function ChatThread({
9192
if (url.includes("/api/copilotkit") && res.status === 428) {
9293
window.dispatchEvent(new CustomEvent("inalpha:open-llm-settings"));
9394
} else if (url.includes("/api/copilotkit") && res.status === 401) {
94-
setChatError("当前 LLM API Key 无效或暂时不可用,请检查配置后重试");
95+
setChatError(tLlm("invalidKey"));
9596
}
9697
return res;
9798
};
9899
(patched as { __inalphaLLMCheck?: boolean }).__inalphaLLMCheck = true;
99100
window.fetch = patched;
100101
return () => { if (window.fetch === patched) window.fetch = orig; };
101-
}, []);
102+
}, [tLlm]);
102103

103104
const loadedThreadRef = useRef<string | null>(null);
104105
const setMessagesRef = useRef(setMessages);
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
"use client";
2+
3+
import { useEffect, useState } from "react";
4+
5+
import { LLMConfigModal } from "./LLMConfigModal";
6+
7+
const LS_DISMISSED = "inalpha-llm-config-dismissed";
8+
9+
/** 在所有控制台页面管理用户 LLM 配置入口。 */
10+
export function LLMConfigGate() {
11+
const [open, setOpen] = useState(false);
12+
13+
useEffect(() => {
14+
const openSettings = () => setOpen(true);
15+
window.addEventListener("inalpha:open-llm-settings", openSettings);
16+
17+
if (!localStorage.getItem(LS_DISMISSED)) {
18+
void fetch("/api/user/settings")
19+
.then((response) => response.ok ? response.json() : null)
20+
.then((settings) => {
21+
if (settings && (!settings.configs || settings.configs.length === 0)) {
22+
setOpen(true);
23+
}
24+
});
25+
}
26+
27+
return () => window.removeEventListener("inalpha:open-llm-settings", openSettings);
28+
}, []);
29+
30+
return (
31+
<LLMConfigModal
32+
open={open}
33+
onClose={() => {
34+
setOpen(false);
35+
localStorage.setItem(LS_DISMISSED, "1");
36+
}}
37+
/>
38+
);
39+
}

0 commit comments

Comments
 (0)