fix(chat): 澄清问题卡片 UX 优化 — 去悬空引用 + 默认展开
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
- 提示词增加 ask_clarification 引用规则,避免 LLM 在文本中生成 "以下信息"/"比如:"等悬空引用短语 - 新增 stripDanglingClarificationRef 前端安全网,当消息包含 ask_clarification 工具调用时自动移除末尾悬空引用 - 澄清卡片默认展开,让用户直接看到选项无需额外点击
This commit is contained in:
@@ -665,6 +665,28 @@ function stripToolNarration(content: string): string {
|
||||
return result || content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip dangling clarification references from text when ask_clarification tool was called.
|
||||
* When the LLM calls ask_clarification, it often ends its text with phrases like
|
||||
* "比如:" / "以下信息" / "以下选项" that reference the tool output — but the tool output
|
||||
* is rendered in a separate ClarificationCard, so these become confusing dead-end sentences.
|
||||
*/
|
||||
function stripDanglingClarificationRef(text: string, hasClarificationTool: boolean): string {
|
||||
if (!hasClarificationTool || !text) return text;
|
||||
// Match trailing dangling references in Chinese and English
|
||||
const patterns = [
|
||||
/[,,]\s*可以(?:提供以下|告诉我更多细节,)?(?:信息|选项|方向|细节|分类|类型)[::]\s*$/,
|
||||
/[,,]\s*比如[::]\s*$/,
|
||||
/[,,]\s*(?:例如|譬如|如以下)[::]\s*$/,
|
||||
/,\s*(?:for example|such as|like|the following)[::]?\s*$/i,
|
||||
];
|
||||
for (const pat of patterns) {
|
||||
const stripped = text.replace(pat, '');
|
||||
if (stripped !== text) return stripped;
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
function MessageBubble({ message, onRetry }: { message: Message; setInput?: (text: string) => void; onRetry?: () => void }) {
|
||||
if (message.role === 'tool') {
|
||||
return null;
|
||||
@@ -749,7 +771,10 @@ function MessageBubble({ message, onRetry }: { message: Message; setInput?: (tex
|
||||
? (isUser
|
||||
? message.content
|
||||
: <StreamingText
|
||||
content={stripToolNarration(message.content)}
|
||||
content={stripDanglingClarificationRef(
|
||||
stripToolNarration(message.content),
|
||||
toolCallSteps?.some(s => s.toolName === 'ask_clarification') ?? false,
|
||||
)}
|
||||
isStreaming={!!message.streaming}
|
||||
className="text-gray-700 dark:text-gray-200"
|
||||
/>
|
||||
|
||||
@@ -166,7 +166,8 @@ interface ToolStepRowProps {
|
||||
}
|
||||
|
||||
function ToolStepRow({ step, isActive, showConnector }: ToolStepRowProps) {
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
// Clarification cards default to expanded so users see options immediately
|
||||
const [expanded, setExpanded] = useState(step.toolName === 'ask_clarification');
|
||||
const Icon = getToolIcon(step.toolName);
|
||||
const label = getToolLabel(step.toolName);
|
||||
const isRunning = step.status === 'running';
|
||||
|
||||
Reference in New Issue
Block a user