From a0d139237181c258482a7a4d50b63a8410964e07 Mon Sep 17 00:00:00 2001 From: iven Date: Thu, 16 Apr 2026 19:12:21 +0800 Subject: [PATCH] =?UTF-8?q?fix(ui):=205=20=E9=A1=B9=20E2E=20=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=20Bug=20=E4=BF=AE=E5=A4=8D=20=E2=80=94=20Agent=20502?= =?UTF-8?q?=20/=20=E9=94=99=E8=AF=AF=E6=8C=81=E4=B9=85=E5=8C=96=20/=20?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E6=A0=87=E8=AE=B0=20/=20=E4=BE=A7=E9=9D=A2?= =?UTF-8?q?=E6=9D=BF=20/=20=E8=AE=B0=E5=BF=86=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - BUG-01: createFromTemplate 在 saas-relay 模式下 try-catch 跳过本地 Kernel - BUG-02: upsertActiveConversation 持久化前剥离 error/streaming/optimistic 字段 - BUG-04: ModelSelector 添加 available 标记,ChatArea 追踪失败模型 ID - BUG-05: VikingPanel 移除 status?.available 门控,不可用时 disabled + 重连按钮 - BUG-06: 侧面板 tooltip 改为"查看产物文件",空状态增加图标和说明 --- desktop/src/components/ChatArea.tsx | 14 ++ desktop/src/components/VikingPanel.tsx | 238 ++++++++++-------- desktop/src/components/ai/ArtifactPanel.tsx | 12 +- desktop/src/components/ai/ModelSelector.tsx | 28 ++- .../src/components/ai/ResizableChatLayout.tsx | 2 +- desktop/src/store/agentStore.ts | 46 +++- desktop/src/store/chat/conversationStore.ts | 10 +- 7 files changed, 219 insertions(+), 131 deletions(-) diff --git a/desktop/src/components/ChatArea.tsx b/desktop/src/components/ChatArea.tsx index cd1aa97..11f683b 100644 --- a/desktop/src/components/ChatArea.tsx +++ b/desktop/src/components/ChatArea.tsx @@ -72,13 +72,27 @@ export function ChatArea({ compact, onOpenDetail }: { compact?: boolean; onOpenD const saasModels = useSaaSStore((s) => s.availableModels); const isLoggedIn = useSaaSStore((s) => s.isLoggedIn); + // Track models that failed with API key errors in this session + const failedModelIds = useRef>(new Set()); + + // Scan messages for API key errors to populate failedModelIds + useEffect(() => { + for (const msg of messages) { + if (msg.error && (msg.error.includes('没有可用的 API Key') || msg.error.includes('Key Pool'))) { + failedModelIds.current.add(currentModel); + } + } + }, [messages, currentModel]); + // Merge models: SaaS available models take priority when logged in const models = useMemo(() => { + const failed = failedModelIds.current; if (isLoggedIn && saasModels.length > 0) { return saasModels.map(m => ({ id: m.alias || m.id, name: m.alias || m.id, provider: m.provider_id, + available: !failed.has(m.alias || m.id), })); } if (configModels.length > 0) { diff --git a/desktop/src/components/VikingPanel.tsx b/desktop/src/components/VikingPanel.tsx index 997d569..675a9c6 100644 --- a/desktop/src/components/VikingPanel.tsx +++ b/desktop/src/components/VikingPanel.tsx @@ -196,68 +196,89 @@ export function VikingPanel() { )} {/* Storage Info */} - {status?.available && ( -
-
-
- +
+
+
+ +
+
+
+ 本地存储
-
-
- 本地存储 -
-
- {status.version || 'Native'} · {status.dataDir || '默认路径'} -
+
+ {status?.available + ? `${status.version || 'Native'} · ${status.dataDir || '默认路径'}` + : '存储未连接'}
-
-
- - SQLite + FTS5 -
-
- - TF-IDF 语义评分 -
- {memoryCount !== null && ( -
- - {memoryCount} 条记忆 -
- )} -
+ {!status?.available && ( + + )}
- )} +
+
+ {status?.available ? ( + + ) : ( + + )} + SQLite + FTS5 +
+
+ {status?.available ? ( + + ) : ( + + )} + TF-IDF 语义评分 +
+ {memoryCount !== null && ( +
+ + {memoryCount} 条记忆 +
+ )} +
+
{/* Search Box */} - {status?.available && ( -
-

语义搜索

-
- setSearchQuery(e.target.value)} - onKeyDown={(e) => e.key === 'Enter' && handleSearch()} - placeholder="输入自然语言查询..." - className="flex-1 px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-900 text-gray-900 dark:text-white text-sm focus:ring-2 focus:ring-blue-500 focus:border-transparent" - /> - -
+
+

语义搜索

+ {!status?.available && ( +

+ 存储未连接,搜索功能不可用 +

+ )} +
+ setSearchQuery(e.target.value)} + onKeyDown={(e) => e.key === 'Enter' && handleSearch()} + placeholder="输入自然语言查询..." + disabled={!status?.available} + className="flex-1 px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-900 text-gray-900 dark:text-white text-sm focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:opacity-50 disabled:cursor-not-allowed" + /> +
- )} +
{/* Search Results */} {searchResults.length > 0 && ( @@ -385,59 +406,64 @@ export function VikingPanel() { )} {/* Summary Generation */} - {status?.available && ( -
-

智能摘要

-

- 存储资源并自动通过 LLM 生成 L0/L1 多级摘要(需配置摘要驱动) +

+

智能摘要

+

+ 存储资源并自动通过 LLM 生成 L0/L1 多级摘要(需配置摘要驱动) +

+ {!status?.available && ( +

+ 存储未连接,摘要功能不可用

-
- setSummaryUri(e.target.value)} - placeholder="资源 URI (如: notes/project-plan)" - className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-900 text-gray-900 dark:text-white text-sm focus:ring-2 focus:ring-blue-500 focus:border-transparent" - /> -