mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-28 06:51:16 +08:00
fix(tui): filter thinking status noise
This commit is contained in:
@@ -150,6 +150,20 @@ describe('createGatewayEventHandler', () => {
|
||||
expect(appended[appended.length - 1]).toMatchObject({ role: 'assistant', text: 'final answer' })
|
||||
})
|
||||
|
||||
it('filters spinner/status-only reasoning noise from completed thinking', () => {
|
||||
const appended: Msg[] = []
|
||||
const streamed = '(¬_¬) synthesizing...\nactual plan\n( ͡° ͜ʖ ͡°) pondering...\nnext step'
|
||||
|
||||
const onEvent = createGatewayEventHandler(buildCtx(appended))
|
||||
|
||||
onEvent({ payload: { text: streamed }, type: 'reasoning.delta' } as any)
|
||||
onEvent({ payload: { text: 'final answer' }, type: 'message.complete' } as any)
|
||||
|
||||
expect(appended[0]?.thinking).toBe(streamed)
|
||||
expect(appended[0]?.text).toBe('')
|
||||
expect(appended[appended.length - 1]).toMatchObject({ role: 'assistant', text: 'final answer' })
|
||||
})
|
||||
|
||||
it('ignores fallback reasoning.available when streamed reasoning already exists', () => {
|
||||
const appended: Msg[] = []
|
||||
const streamed = 'short streamed reasoning'
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import { hasReasoningTag, splitReasoning } from '../lib/reasoning.js'
|
||||
import { cleanThinkingText } from '../lib/text.js'
|
||||
|
||||
describe('splitReasoning', () => {
|
||||
it('extracts <think>…</think> and strips it from text', () => {
|
||||
@@ -48,3 +49,13 @@ describe('splitReasoning', () => {
|
||||
expect(hasReasoningTag('no tags at all')).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('cleanThinkingText', () => {
|
||||
it('removes face/status ticker fragments while preserving real reasoning', () => {
|
||||
expect(
|
||||
cleanThinkingText(
|
||||
'(¬_¬) synthesizing...**Resolving comments on GitHub**\n( ͡° ͜ʖ ͡°) musing...\nActual step\n٩(๑❛ᴗ❛๑)۶ contemplating...next step'
|
||||
)
|
||||
).toBe('**Resolving comments on GitHub**\nActual step\nnext step')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -70,8 +70,43 @@ export const pasteTokenLabel = (text: string, lineCount: number) => {
|
||||
: `[[ ${preview} [${fmtK(lineCount)} lines] ]]`
|
||||
}
|
||||
|
||||
const THINKING_STATUS_WORDS = [
|
||||
'pondering',
|
||||
'contemplating',
|
||||
'musing',
|
||||
'cogitating',
|
||||
'ruminating',
|
||||
'deliberating',
|
||||
'mulling',
|
||||
'reflecting',
|
||||
'processing',
|
||||
'reasoning',
|
||||
'analyzing',
|
||||
'computing',
|
||||
'synthesizing',
|
||||
'formulating',
|
||||
'brainstorming'
|
||||
]
|
||||
|
||||
const THINKING_STATUS_RE = new RegExp(`^(?:${THINKING_STATUS_WORDS.join('|')})\\.{0,3}$`, 'i')
|
||||
|
||||
const THINKING_FACE_SOURCE = '[^A-Za-z\n]+'
|
||||
|
||||
const THINKING_STATUS_CHUNK_RE = new RegExp(
|
||||
`${THINKING_FACE_SOURCE}\\s*(?:${THINKING_STATUS_WORDS.join('|')})\\.{0,3}\\s*`,
|
||||
'giu'
|
||||
)
|
||||
|
||||
export const cleanThinkingText = (reasoning: string) =>
|
||||
reasoning
|
||||
.split('\n')
|
||||
.map(line => line.replace(THINKING_STATUS_CHUNK_RE, '').trim())
|
||||
.filter(line => line && !THINKING_STATUS_RE.test(line.replace(/\.\.\.$/, '').trim()))
|
||||
.join('\n')
|
||||
.trim()
|
||||
|
||||
export const thinkingPreview = (reasoning: string, mode: ThinkingMode, max: number = THINKING_COT_MAX) => {
|
||||
const raw = reasoning.trim()
|
||||
const raw = cleanThinkingText(reasoning)
|
||||
|
||||
return !raw || mode === 'collapsed' ? '' : mode === 'full' ? raw : compactPreview(raw.replace(WS_RE, ' '), max)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user