diff --git a/apps/ai-game-creator-shell/src/features/project-workspace/usePromptPolish.ts b/apps/ai-game-creator-shell/src/features/project-workspace/usePromptPolish.ts index e8506823b..63511fb74 100644 --- a/apps/ai-game-creator-shell/src/features/project-workspace/usePromptPolish.ts +++ b/apps/ai-game-creator-shell/src/features/project-workspace/usePromptPolish.ts @@ -1,5 +1,6 @@ import { useCallback, useRef, useState } from 'react'; +import { visibleClientErrorMessage } from '../../services/errorReporting'; import { requestChatPromptPolish } from './chatPromptPolish'; /** @@ -143,11 +144,12 @@ export function usePromptPolish({ setNotice(normalized.notice ?? null); applyPrompt(normalized.text); return normalized.text; - } catch { - // 注入的 `requestPolish` / 规范化 / 回填都可能抛:兜成失败提示, - // 而不是把这个 promise 变成未处理拒绝、让用户看不到任何反馈。 + } catch (error) { + // 注入的 requestPolish / 规范化 / 回填 都可能抛:保留安全正文, + // 不让“可重试”固定句吞掉平台、IPC 或宿主错误。 if (requestIdRef.current === requestId) { - setError(options?.failureMessage ?? failureMessage); + const summary = options?.failureMessage ?? failureMessage; + setError(`${summary}:${visibleClientErrorMessage(error)}`); } return null; } finally { diff --git a/apps/ai-game-creator-shell/tests/usePromptPolish.test.tsx b/apps/ai-game-creator-shell/tests/usePromptPolish.test.tsx index e0c97e61f..50ef523bb 100644 --- a/apps/ai-game-creator-shell/tests/usePromptPolish.test.tsx +++ b/apps/ai-game-creator-shell/tests/usePromptPolish.test.tsx @@ -54,7 +54,9 @@ describe('usePromptPolish', () => { // 默认 `requestChatPromptPolish` 自己吞掉失败;注入实现可以拒绝,此时必须 // 变成用户可见的失败提示,而不是把 promise 变成未处理拒绝、界面上什么都没有。 expect(returned).toBeNull(); - expect(result.current.error).toBe('AI 润色失败,可重试'); + expect(result.current.error).toBe( + 'AI 润色失败,可重试:platform llm unavailable', + ); expect(result.current.polishing).toBe(false); expect(applyPrompt).not.toHaveBeenCalled(); }); @@ -72,7 +74,9 @@ describe('usePromptPolish', () => { await result.current.polish({ failureMessage: '润色失败,可直接发送' }); }); - expect(result.current.error).toBe('润色失败,可直接发送'); + expect(result.current.error).toBe( + '润色失败,可直接发送:composer write failed', + ); expect(result.current.polishing).toBe(false); }); diff --git a/docs/adr/【ADR】AGC命令错误结构化与错误报告口径-2026-10-01.md b/docs/adr/【ADR】AGC命令错误结构化与错误报告口径-2026-10-01.md index 24bcd8eec..9d5823eed 100644 --- a/docs/adr/【ADR】AGC命令错误结构化与错误报告口径-2026-10-01.md +++ b/docs/adr/【ADR】AGC命令错误结构化与错误报告口径-2026-10-01.md @@ -138,6 +138,7 @@ DirectProject 已经解决过同一类问题([`【ADR】DirectProject命令接 - 跨项目活动回合快照读取失败即使保留旧快照,也必须把最近一次安全正文一并呈现;“读不到不等于没有在跑”不能变成“读不到所以没有原因”。 - 项目打开前的权限策略读取属于 IPC 边界,失败不得静默中止加载;必须保留安全正文并标明是策略读取失败。 - 错误报告通知自身的快照读取失败也不能被通知组件的重试逻辑吞掉;重试耗尽后必须显示安全正文和再次读取入口。 +- 共享异步操作 hook(包括 Prompt Polish)捕获异常时,操作指引可以保留,但固定失败文案后必须附精确脱敏正文。 ## 后果与边界 diff --git a/docs/project-memory/plans/【里程碑】AGC错误具体文本展示-2026-10-04.md b/docs/project-memory/plans/【里程碑】AGC错误具体文本展示-2026-10-04.md index 2791df445..3322c34b4 100644 --- a/docs/project-memory/plans/【里程碑】AGC错误具体文本展示-2026-10-04.md +++ b/docs/project-memory/plans/【里程碑】AGC错误具体文本展示-2026-10-04.md @@ -59,3 +59,4 @@ DirectProject 回合失败在确认不是客户端内部不可归类故障时, - 窗口标题栏的 Direct 活动回合快照读取失败原来只给“读取失败”标志并保留旧快照;现额外保留脱敏后的 IPC/读取正文,面板不会把真实原因吞掉。 - 项目打开时读取 `conversation.read` 权限策略的 IPC 失败原来静默 return;现把脱敏错误正文写入项目状态和聊天错误提示。 - 错误报告通知读取本地待报告快照失败原来只重试后静默消失;现显示“项目诊断读取失败”及安全正文,并提供重试入口。 +- 共享 Prompt Polish hook 的注入请求/规范化/回填异常原来只显示固定失败提示;现保留精确脱敏后的异常正文,聊天输入和资源润色共用同一口径。