继续收敛模型配置读取错误

保留模型目录与选择器配置 IPC 的脱敏正文

更新模型选择器具体错误回归测试
This commit is contained in:
kdletters
2026-10-06 01:17:16 +08:00
parent 1ce8625585
commit f3e48db252
4 changed files with 20 additions and 8 deletions
@@ -154,10 +154,16 @@ export function ConversationModelSelect({
await waitForConfigWrite();
if (selectionEpochRef.current !== epochAtRequest)
return Boolean(selectedRef.current);
const config = await invoke<GameCreatorAppConfigView>(
'read_game_creator_app_config',
).catch(() => null);
if (!config) throw new ModelSelectionConfigError('读取客户端配置失败');
let config: GameCreatorAppConfigView;
try {
config = await invoke<GameCreatorAppConfigView>(
'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;
@@ -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;
@@ -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(<ConversationModelSelect disabled={false} onReady={onReady} />);
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 () => {
@@ -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)` 后只显示“读取客户端配置失败”;现通过统一可见错误脱敏出口保留具体正文,并保留配置不可读时不猜测模型路由的安全行为。