From 77f1ea8350ac7750f57313e9ff7c0e13064dc906 Mon Sep 17 00:00:00 2001 From: john Date: Tue, 14 Jul 2026 14:24:32 +0800 Subject: [PATCH] fix(ui): harden product-facing interaction flows --- conversation-display.test.mjs | 7 +++++++ scripts/verify-chat-finish-sync.mjs | 5 +++++ src/components/MindSpacePageDetail.tsx | 14 ++++++++++---- src/components/MindSpaceView.tsx | 4 ++++ src/components/VoiceInputDialog.tsx | 11 ++++++++++- src/utils/message.ts | 2 +- 6 files changed, 37 insertions(+), 6 deletions(-) diff --git a/conversation-display.test.mjs b/conversation-display.test.mjs index c721a45..45c0703 100644 --- a/conversation-display.test.mjs +++ b/conversation-display.test.mjs @@ -25,6 +25,13 @@ test('deriveUserFacingText removes routing hint and skill preface from agent pay assert.equal(deriveUserFacingText(agentPayload), userText); }); +test('deriveUserFacingText removes page-data prompt persisted as display text', () => { + const userText = '帮我做一个日记页面,可以每天写日记,其他人可以评价'; + const persistedDisplayText = `${buildAutoChatSkillPrefix(userText, ['page-data-collect'])}${userText}`; + assert.match(persistedDisplayText, /page-data-collect/); + assert.equal(deriveUserFacingText(persistedDisplayText), userText); +}); + test('deriveUserFacingText removes Memind task orchestration prefix', () => { const userText = '帮我生成深度搜索报告'; const agentPayload = [ diff --git a/scripts/verify-chat-finish-sync.mjs b/scripts/verify-chat-finish-sync.mjs index ef21177..3366b1c 100644 --- a/scripts/verify-chat-finish-sync.mjs +++ b/scripts/verify-chat-finish-sync.mjs @@ -36,6 +36,11 @@ const messageTs = read('src/utils/message.ts'); assertIncludes(messageTs, 'deriveUserFacingText', 'message.ts'); assertIncludes(messageTs, 'deriveAssistantFacingText', 'message.ts'); assertIncludes(messageTs, 'chat-finish-sync.mjs', 'message.ts'); +assertIncludes( + messageTs, + 'deriveUserFacingText(message.metadata.displayText)', + 'message.ts metadata displayText guard', +); const conversationDisplay = read('conversation-display.mjs'); assertIncludes(conversationDisplay, 'TASK_ROUTING_HINT_RE', 'conversation-display.mjs'); diff --git a/src/components/MindSpacePageDetail.tsx b/src/components/MindSpacePageDetail.tsx index 552f850..7920393 100644 --- a/src/components/MindSpacePageDetail.tsx +++ b/src/components/MindSpacePageDetail.tsx @@ -1586,7 +1586,7 @@ export function MindSpacePageDetail({ diff --git a/src/components/MindSpaceView.tsx b/src/components/MindSpaceView.tsx index cd35d4c..59c2911 100644 --- a/src/components/MindSpaceView.tsx +++ b/src/components/MindSpaceView.tsx @@ -477,6 +477,10 @@ function formatBytes(bytes: number) { type AssetFilter = 'all' | 'images' | 'files' | 'pages'; +function previewBlocked() { + return new Error('预览模式仅供查看,不能修改内容'); +} + function canGenerateWithAgent(asset: MindSpaceAsset) { const textLikeMimeTypes = new Set([ 'text/plain', diff --git a/src/components/VoiceInputDialog.tsx b/src/components/VoiceInputDialog.tsx index a4e01e2..9833b89 100644 --- a/src/components/VoiceInputDialog.tsx +++ b/src/components/VoiceInputDialog.tsx @@ -17,7 +17,16 @@ export function VoiceInputDialog({ onSend: (text: string) => void; onError?: (message: string) => void; }) { - const { phase, text, analyser, liveRecognition, stopListening, finishFallbackRecording, resetSession } = + const { + phase, + text, + analyser, + liveRecognition, + updateText, + stopListening, + finishFallbackRecording, + resetSession, + } = useVoiceSession({ active: open && !disabled, onError, diff --git a/src/utils/message.ts b/src/utils/message.ts index 14f0b9d..4f40ad5 100644 --- a/src/utils/message.ts +++ b/src/utils/message.ts @@ -204,7 +204,7 @@ export function getDisplayText(message: Message): string { // REGRESSION GUARD: never show agent-only routing/skill prefixes in the chat UI. if (message.role === 'user') { if ('displayText' in message.metadata && message.metadata.displayText != null) { - return stripImageUrlLines(message.metadata.displayText); + return stripImageUrlLines(deriveUserFacingText(message.metadata.displayText)); } const raw = message.content .filter((c): c is Extract => c.type === 'text')