From f3e48db252c6697090fccb464017ae54628a3895 Mon Sep 17 00:00:00 2001 From: kdletters <61648117+kdletters@users.noreply.github.com> Date: Tue, 6 Oct 2026 01:17:16 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=A7=E7=BB=AD=E6=94=B6=E6=95=9B=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E9=85=8D=E7=BD=AE=E8=AF=BB=E5=8F=96=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 保留模型目录与选择器配置 IPC 的脱敏正文 更新模型选择器具体错误回归测试 --- .../project-workspace/ConversationModelSelect.tsx | 14 ++++++++++---- .../src/services/llmModelCatalog.ts | 5 ++++- .../tests/conversationModelSelect.test.tsx | 8 +++++--- .../【里程碑】AGC错误具体文本展示-2026-10-04.md | 1 + 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/apps/ai-game-creator-shell/src/features/project-workspace/ConversationModelSelect.tsx b/apps/ai-game-creator-shell/src/features/project-workspace/ConversationModelSelect.tsx index 158defded..0170a4d51 100644 --- a/apps/ai-game-creator-shell/src/features/project-workspace/ConversationModelSelect.tsx +++ b/apps/ai-game-creator-shell/src/features/project-workspace/ConversationModelSelect.tsx @@ -154,10 +154,16 @@ export function ConversationModelSelect({ await waitForConfigWrite(); if (selectionEpochRef.current !== epochAtRequest) return Boolean(selectedRef.current); - const config = await invoke( - 'read_game_creator_app_config', - ).catch(() => null); - if (!config) throw new ModelSelectionConfigError('读取客户端配置失败'); + let config: GameCreatorAppConfigView; + try { + config = await invoke( + 'read_game_creator_app_config', + ); + } catch (error) { + throw new ModelSelectionConfigError( + `读取客户端配置失败:${visibleClientErrorMessage(error)}`, + ); + } if (selectionEpochRef.current !== epochAtRequest) return Boolean(selectedRef.current); const saved = config.config.selectedModelId; diff --git a/apps/ai-game-creator-shell/src/services/llmModelCatalog.ts b/apps/ai-game-creator-shell/src/services/llmModelCatalog.ts index 0fd46c689..472162121 100644 --- a/apps/ai-game-creator-shell/src/services/llmModelCatalog.ts +++ b/apps/ai-game-creator-shell/src/services/llmModelCatalog.ts @@ -1,6 +1,7 @@ import { resolveTauriInvoke } from '../app/tauri'; import type { GameCreatorAppConfigView } from '../app/types'; import { type ClientLlmModelCatalog, loadClientLlmModels } from './clientApi'; +import { visibleClientErrorMessage } from './errorReporting'; export type { ClientLlmModel, ClientLlmModelCatalog } from './clientApi'; @@ -32,7 +33,9 @@ async function loadEffectiveCatalog(epoch: number) { ); } catch (error) { if (epoch === generation) cached = null; - throw new LlmModelCatalogConfigError('读取客户端配置失败'); + throw new LlmModelCatalogConfigError( + `读取客户端配置失败:${visibleClientErrorMessage(error)}`, + ); } if (epoch !== generation) throw new Error('模型配置已更新'); const llm = config?.config.llm; diff --git a/apps/ai-game-creator-shell/tests/conversationModelSelect.test.tsx b/apps/ai-game-creator-shell/tests/conversationModelSelect.test.tsx index c2a5c252f..519c75b7f 100644 --- a/apps/ai-game-creator-shell/tests/conversationModelSelect.test.tsx +++ b/apps/ai-game-creator-shell/tests/conversationModelSelect.test.tsx @@ -352,7 +352,7 @@ test('a failed save keeps submission unavailable', async () => { await screen.findByRole('button', { name: '对话模型' }); fireEvent.click(screen.getByRole('button', { name: '对话模型' })); fireEvent.click(screen.getByRole('option', { name: '快速' })); - await screen.findByText('模型选择保存失败'); + await screen.findByText('disk full'); expect(onReady).toHaveBeenLastCalledWith(false); }); @@ -595,7 +595,7 @@ test('recovers the selector when reading the native config fails', async () => { invoke.mockRejectedValueOnce(new Error('config unreadable')); const onReady = vi.fn(); render(); - await screen.findByText('读取客户端配置失败'); + await screen.findByText('读取客户端配置失败:config unreadable'); await waitFor(() => expect(onReady).toHaveBeenLastCalledWith(false)); // 配置不可读时不能猜测官方路由;恢复读取后选项与刷新按钮重新可用。 @@ -605,7 +605,9 @@ test('recovers the selector when reading the native config fails', async () => { expect(option.hasAttribute('disabled')).toBe(false); fireEvent.click(screen.getByRole('button', { name: '刷新模型列表' })); await waitFor(() => expect(onReady).toHaveBeenLastCalledWith(true)); - expect(screen.queryByText('读取客户端配置失败')).toBeNull(); + expect( + screen.queryByText('读取客户端配置失败:config unreadable'), + ).toBeNull(); }); test('pre-send validation waits for an in-flight selection save', async () => { diff --git a/docs/project-memory/plans/【里程碑】AGC错误具体文本展示-2026-10-04.md b/docs/project-memory/plans/【里程碑】AGC错误具体文本展示-2026-10-04.md index 973ba6c01..c704494f4 100644 --- a/docs/project-memory/plans/【里程碑】AGC错误具体文本展示-2026-10-04.md +++ b/docs/project-memory/plans/【里程碑】AGC错误具体文本展示-2026-10-04.md @@ -89,3 +89,4 @@ DirectProject 回合失败在确认不是客户端内部不可归类故障时, - CC/Direct 工具桥的执行前后成果指纹、回执结算 JoinError/落盘失败,以及外部 MCP journal 的读取/JSON 行解析原先仍会被 `.ok()`、固定回执句或“无记录”吞掉;现分别保留指纹阶段、回执任务/落盘原因、journal 行号和底层正文,只有真实 `NotFound` 才视为空记录。 - 外部 MCP `resources/read` 仍把已能返回具体原因的 Codex journal 读取错误 `unwrap_or_default()` 成空资源;现把读取失败按 MCP 错误响应返回,Direct 执行会话当前项目 canonicalize 也保留底层 I/O 正文。 - Direct 交付终态读取原先把 `session.snapshot()` 锁/状态错误折叠成 `None`,上层继续显示“尚未确认交付完成”;现沿 `code-generation` 失败出口保留终态读取正文,并在已有回合失败时同时保留原始失败与终态读取失败。 +- 对话模型选择器读取 native 配置原先把 IPC/文件异常 `.catch(() => null)` 后只显示“读取客户端配置失败”;现通过统一可见错误脱敏出口保留具体正文,并保留配置不可读时不猜测模型路由的安全行为。