fix(ui): harden product-facing interaction flows
This commit is contained in:
@@ -25,6 +25,13 @@ test('deriveUserFacingText removes routing hint and skill preface from agent pay
|
|||||||
assert.equal(deriveUserFacingText(agentPayload), userText);
|
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', () => {
|
test('deriveUserFacingText removes Memind task orchestration prefix', () => {
|
||||||
const userText = '帮我生成深度搜索报告';
|
const userText = '帮我生成深度搜索报告';
|
||||||
const agentPayload = [
|
const agentPayload = [
|
||||||
|
|||||||
@@ -36,6 +36,11 @@ const messageTs = read('src/utils/message.ts');
|
|||||||
assertIncludes(messageTs, 'deriveUserFacingText', 'message.ts');
|
assertIncludes(messageTs, 'deriveUserFacingText', 'message.ts');
|
||||||
assertIncludes(messageTs, 'deriveAssistantFacingText', 'message.ts');
|
assertIncludes(messageTs, 'deriveAssistantFacingText', 'message.ts');
|
||||||
assertIncludes(messageTs, 'chat-finish-sync.mjs', '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');
|
const conversationDisplay = read('conversation-display.mjs');
|
||||||
assertIncludes(conversationDisplay, 'TASK_ROUTING_HINT_RE', 'conversation-display.mjs');
|
assertIncludes(conversationDisplay, 'TASK_ROUTING_HINT_RE', 'conversation-display.mjs');
|
||||||
|
|||||||
@@ -1586,7 +1586,7 @@ export function MindSpacePageDetail({
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={previewRefreshPending ? 'is-refresh-pending' : undefined}
|
className={previewRefreshPending ? 'is-refresh-pending' : undefined}
|
||||||
onClick={handleManualPreviewRefresh}
|
onClick={() => handleManualPreviewRefresh()}
|
||||||
title={previewRefreshPending ? '草稿已有新内容,点击刷新预览' : '将当前草稿同步到预览'}
|
title={previewRefreshPending ? '草稿已有新内容,点击刷新预览' : '将当前草稿同步到预览'}
|
||||||
>
|
>
|
||||||
刷新预览{previewRefreshPending ? ' · 有新修改' : ''}
|
刷新预览{previewRefreshPending ? ' · 有新修改' : ''}
|
||||||
@@ -1684,15 +1684,21 @@ export function MindSpacePageDetail({
|
|||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{confirmPublicationStatusOpen && page?.publication ? (
|
{confirmPublicationStatusOpen && page?.publication ? (
|
||||||
<MindSpaceModal className="mindspace-confirm-publication-status-modal">
|
<MindSpaceModal
|
||||||
|
open={confirmPublicationStatusOpen}
|
||||||
|
onClose={() => setConfirmPublicationStatusOpen(false)}
|
||||||
|
title="页面预览期确认"
|
||||||
|
eyebrow="PUBLICATION STATUS"
|
||||||
|
className="mindspace-confirm-publication-status-modal"
|
||||||
|
disableClose={statusConfirming}
|
||||||
|
>
|
||||||
<div className="mindspace-modal-content">
|
<div className="mindspace-modal-content">
|
||||||
<h3>页面预览期确认</h3>
|
|
||||||
<p>你的页面当前处于 30 分钟预览期。请选择后续状态:</p>
|
<p>你的页面当前处于 30 分钟预览期。请选择后续状态:</p>
|
||||||
<div className="mindspace-modal-actions">
|
<div className="mindspace-modal-actions">
|
||||||
<button
|
<button
|
||||||
className="mindspace-secondary"
|
className="mindspace-secondary"
|
||||||
disabled={statusConfirming}
|
disabled={statusConfirming}
|
||||||
onClick={() => confirmPublicationStatus('private')}
|
onClick={() => confirmPublicationStatus('owner_only')}
|
||||||
>
|
>
|
||||||
{statusConfirming ? '处理中...' : '改为私有'}
|
{statusConfirming ? '处理中...' : '改为私有'}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -477,6 +477,10 @@ function formatBytes(bytes: number) {
|
|||||||
|
|
||||||
type AssetFilter = 'all' | 'images' | 'files' | 'pages';
|
type AssetFilter = 'all' | 'images' | 'files' | 'pages';
|
||||||
|
|
||||||
|
function previewBlocked() {
|
||||||
|
return new Error('预览模式仅供查看,不能修改内容');
|
||||||
|
}
|
||||||
|
|
||||||
function canGenerateWithAgent(asset: MindSpaceAsset) {
|
function canGenerateWithAgent(asset: MindSpaceAsset) {
|
||||||
const textLikeMimeTypes = new Set([
|
const textLikeMimeTypes = new Set([
|
||||||
'text/plain',
|
'text/plain',
|
||||||
|
|||||||
@@ -17,7 +17,16 @@ export function VoiceInputDialog({
|
|||||||
onSend: (text: string) => void;
|
onSend: (text: string) => void;
|
||||||
onError?: (message: string) => void;
|
onError?: (message: string) => void;
|
||||||
}) {
|
}) {
|
||||||
const { phase, text, analyser, liveRecognition, stopListening, finishFallbackRecording, resetSession } =
|
const {
|
||||||
|
phase,
|
||||||
|
text,
|
||||||
|
analyser,
|
||||||
|
liveRecognition,
|
||||||
|
updateText,
|
||||||
|
stopListening,
|
||||||
|
finishFallbackRecording,
|
||||||
|
resetSession,
|
||||||
|
} =
|
||||||
useVoiceSession({
|
useVoiceSession({
|
||||||
active: open && !disabled,
|
active: open && !disabled,
|
||||||
onError,
|
onError,
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ export function getDisplayText(message: Message): string {
|
|||||||
// REGRESSION GUARD: never show agent-only routing/skill prefixes in the chat UI.
|
// REGRESSION GUARD: never show agent-only routing/skill prefixes in the chat UI.
|
||||||
if (message.role === 'user') {
|
if (message.role === 'user') {
|
||||||
if ('displayText' in message.metadata && message.metadata.displayText != null) {
|
if ('displayText' in message.metadata && message.metadata.displayText != null) {
|
||||||
return stripImageUrlLines(message.metadata.displayText);
|
return stripImageUrlLines(deriveUserFacingText(message.metadata.displayText));
|
||||||
}
|
}
|
||||||
const raw = message.content
|
const raw = message.content
|
||||||
.filter((c): c is Extract<MessageContent, { type: 'text' }> => c.type === 'text')
|
.filter((c): c is Extract<MessageContent, { type: 'text' }> => c.type === 'text')
|
||||||
|
|||||||
Reference in New Issue
Block a user