feat(agent): control reasoning visibility
This commit is contained in:
@@ -7,58 +7,63 @@ const props = defineProps<{
|
||||
messageId: string;
|
||||
role: "user" | "assistant";
|
||||
content: string;
|
||||
reasoning?: string;
|
||||
showReasoning?: boolean;
|
||||
createdAt: string;
|
||||
streaming?: boolean;
|
||||
}>();
|
||||
|
||||
const markdown = new MarkdownIt({ breaks: true, html: false, linkify: true });
|
||||
|
||||
const parsed = computed(() => splitReasoning(props.content));
|
||||
const answer = computed(() => {
|
||||
if (props.role === "user") return props.content;
|
||||
return stripStreamingReasoning(props.content).replace(/^\s+/, "");
|
||||
return parsed.value.answer.replace(/^\s+/, "");
|
||||
});
|
||||
|
||||
const reasoning = computed(() => props.reasoning || parsed.value.reasoning);
|
||||
const hasAnswer = computed(() => answer.value.trim().length > 0);
|
||||
|
||||
const renderedContent = computed(() => {
|
||||
if (props.role !== "assistant") return answer.value;
|
||||
return hasAnswer.value ? markdown.render(answer.value) : "";
|
||||
});
|
||||
|
||||
function stripStreamingReasoning(content: string) {
|
||||
function splitReasoning(content: string) {
|
||||
const lower = content.toLowerCase();
|
||||
let visible = "";
|
||||
let answer = "";
|
||||
let reasoning = "";
|
||||
let cursor = 0;
|
||||
let reasoningDepth = 0;
|
||||
let depth = 0;
|
||||
while (cursor < content.length) {
|
||||
const tagStart = content.indexOf("<", cursor);
|
||||
if (tagStart === -1) {
|
||||
if (reasoningDepth === 0) visible += content.slice(cursor);
|
||||
if (depth) reasoning += content.slice(cursor);
|
||||
else answer += content.slice(cursor);
|
||||
break;
|
||||
}
|
||||
if (reasoningDepth === 0) visible += content.slice(cursor, tagStart);
|
||||
const text = content.slice(cursor, tagStart);
|
||||
if (depth) reasoning += text;
|
||||
else answer += text;
|
||||
const tail = lower.slice(tagStart);
|
||||
const openTag = tail.match(/^<think(?:\s[^>]*)?>/);
|
||||
if (openTag) {
|
||||
reasoningDepth += 1;
|
||||
depth += 1;
|
||||
cursor = tagStart + openTag[0].length;
|
||||
continue;
|
||||
}
|
||||
const closeTag = tail.match(/^<\/think\s*>/);
|
||||
if (closeTag) {
|
||||
reasoningDepth = Math.max(0, reasoningDepth - 1);
|
||||
depth = Math.max(0, depth - 1);
|
||||
cursor = tagStart + closeTag[0].length;
|
||||
continue;
|
||||
}
|
||||
if ("<think".startsWith(tail) || "</think>".startsWith(tail)) break;
|
||||
if (reasoningDepth === 0) visible += "<";
|
||||
if (depth) reasoning += "<";
|
||||
else answer += "<";
|
||||
cursor = tagStart + 1;
|
||||
}
|
||||
return visible;
|
||||
return { answer, reasoning };
|
||||
}
|
||||
|
||||
const displayTime = computed(() => {
|
||||
// 消息服务返回的是 UTC 无时区字符串,补齐时区后再按用户本地时间展示。
|
||||
const normalized = /(?:Z|[+-]\d{2}:?\d{2})$/i.test(props.createdAt) ? props.createdAt : `${props.createdAt}Z`;
|
||||
const date = new Date(normalized);
|
||||
if (Number.isNaN(date.getTime())) return "";
|
||||
@@ -73,6 +78,10 @@ const displayTime = computed(() => {
|
||||
</div>
|
||||
<div class="message-bubble">
|
||||
<template v-if="role === 'assistant'">
|
||||
<details v-if="showReasoning && reasoning.trim()" class="reasoning-panel" :open="streaming">
|
||||
<summary>思考过程</summary>
|
||||
<div class="reasoning-content">{{ reasoning }}</div>
|
||||
</details>
|
||||
<div v-if="renderedContent" class="message-content markdown-content" v-html="renderedContent"></div>
|
||||
<div v-if="streaming && !renderedContent" class="generation-state">
|
||||
<span></span><span></span><span></span>
|
||||
|
||||
@@ -7,6 +7,8 @@ export interface DisplayMessage {
|
||||
id: string;
|
||||
role: "user" | "assistant";
|
||||
content: string;
|
||||
reasoning?: string;
|
||||
showReasoning?: boolean;
|
||||
createdAt: string;
|
||||
streaming?: boolean;
|
||||
}
|
||||
@@ -57,6 +59,8 @@ defineExpose({ scrollToBottom, scrollToMessage });
|
||||
:message-id="message.id"
|
||||
:role="message.role"
|
||||
:content="message.content"
|
||||
:reasoning="message.reasoning"
|
||||
:show-reasoning="message.showReasoning"
|
||||
:created-at="message.createdAt"
|
||||
:streaming="message.streaming"
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user