fix(chat): separate merged output segments
This commit is contained in:
@@ -228,6 +228,14 @@ const parsedThinking = computed(() =>
|
||||
parseThinking(props.message.content || "", { streaming: !!props.message.isStreaming }),
|
||||
);
|
||||
|
||||
const segmentBoundary = '\uE000hermes-output-boundary\uE001';
|
||||
const assistantBodySegments = computed(() => {
|
||||
const segments = props.message.contentSegments;
|
||||
if (!segments || segments.length < 2) return parsedThinking.value.body ? [parsedThinking.value.body] : [];
|
||||
const parsed = parseThinking(segments.join(segmentBoundary), { streaming: !!props.message.isStreaming });
|
||||
return parsed.body.split(segmentBoundary).filter(segment => segment.trim());
|
||||
});
|
||||
|
||||
// 优先使用来自 reasoning 字段/事件的思考文本;否则回退到从 content 解析的 <think> 标签。
|
||||
// 若两者共存,则拼接展示(罕见,但保持信息不丢)。
|
||||
const hasReasoningField = computed(() => !!(props.message.reasoning && props.message.reasoning.length > 0));
|
||||
@@ -1111,11 +1119,12 @@ onBeforeUnmount(() => {
|
||||
<MarkdownRenderer :content="thinkingFullText" />
|
||||
</div>
|
||||
</div>
|
||||
<MarkdownRenderer
|
||||
v-if="parsedThinking.body && message.role === 'assistant'"
|
||||
:content="parsedThinking.body"
|
||||
:heading-id-prefix="effectiveHeadingIdPrefix"
|
||||
/>
|
||||
<template v-if="message.role === 'assistant'">
|
||||
<template v-for="(segment, index) in assistantBodySegments" :key="index">
|
||||
<hr v-if="index > 0" class="assistant-segment-divider" />
|
||||
<MarkdownRenderer :content="segment" :heading-id-prefix="index ? `${effectiveHeadingIdPrefix}-${index}` : effectiveHeadingIdPrefix" />
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<!-- Render user message content -->
|
||||
<template v-if="message.role === 'user'">
|
||||
@@ -1160,7 +1169,7 @@ onBeforeUnmount(() => {
|
||||
|
||||
<!-- Render assistant message content -->
|
||||
<MarkdownRenderer
|
||||
v-if="message.role === 'assistant' && message.content && !parsedThinking.body"
|
||||
v-if="message.role === 'assistant' && message.content && !assistantBodySegments.length"
|
||||
:content="message.content"
|
||||
:heading-id-prefix="effectiveHeadingIdPrefix"
|
||||
/>
|
||||
@@ -1647,6 +1656,12 @@ onBeforeUnmount(() => {
|
||||
}
|
||||
}
|
||||
|
||||
.assistant-segment-divider {
|
||||
border: 0;
|
||||
border-top: 1px solid var(--color-border-2);
|
||||
margin: 12px 0;
|
||||
}
|
||||
|
||||
.message-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -910,7 +910,7 @@ defineExpose({
|
||||
}
|
||||
|
||||
.run-end {
|
||||
margin: 20px auto;
|
||||
margin: -12px auto 0;
|
||||
text-align: center;
|
||||
color: var(--color-text-3);
|
||||
font-size: 12px;
|
||||
|
||||
@@ -14,6 +14,7 @@ export function groupRunMessages(messages: Message[], runActive: boolean): Messa
|
||||
result.push({
|
||||
...first,
|
||||
toolMessages: tools.length ? tools : undefined,
|
||||
contentSegments: assistants.map(m => m.content).filter(text => text.trim()),
|
||||
id: assistants[assistants.length - 1].id,
|
||||
content: assistants.map(m => m.content).filter(text => text.trim()).join('\n\n'),
|
||||
reasoning: assistants.map(m => m.reasoning).filter(Boolean).join('\n\n') || undefined,
|
||||
|
||||
@@ -65,6 +65,7 @@ export interface Message {
|
||||
queued?: boolean
|
||||
systemType?: 'command' | 'error' | 'fork-divider' | 'run-end' | 'tool-group'
|
||||
toolMessages?: Message[]
|
||||
contentSegments?: string[]
|
||||
commandAction?: string
|
||||
commandData?: Record<string, unknown>
|
||||
finishReason?: string | null
|
||||
|
||||
Reference in New Issue
Block a user