mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-28 06:51:16 +08:00
fix(tui): avoid duplicating flushed stream text
This commit is contained in:
@@ -198,6 +198,22 @@ describe('createGatewayEventHandler', () => {
|
||||
expect(appended[3]?.text).not.toContain('```diff')
|
||||
})
|
||||
|
||||
it('keeps full final responses from duplicating flushed pre-diff narration', () => {
|
||||
const appended: Msg[] = []
|
||||
const onEvent = createGatewayEventHandler(buildCtx(appended))
|
||||
const diff = '--- a/foo.ts\n+++ b/foo.ts\n@@\n-old\n+new'
|
||||
const block = `\`\`\`diff\n${diff}\n\`\`\``
|
||||
|
||||
onEvent({ payload: { text: 'Before edit. ' }, type: 'message.delta' } as any)
|
||||
onEvent({ payload: { context: 'foo.ts', name: 'patch', tool_id: 'tool-1' }, type: 'tool.start' } as any)
|
||||
onEvent({ payload: { inline_diff: diff, summary: 'patched', tool_id: 'tool-1' }, type: 'tool.complete' } as any)
|
||||
onEvent({ payload: { text: 'After edit.' }, type: 'message.delta' } as any)
|
||||
onEvent({ payload: { text: 'Before edit. After edit.' }, type: 'message.complete' } as any)
|
||||
|
||||
expect(appended.map(msg => msg.text.trim()).filter(Boolean)).toEqual(['Before edit.', block, 'After edit.'])
|
||||
expect(appended[1]?.tools?.[0]).toContain('Patch')
|
||||
})
|
||||
|
||||
it('drops the diff segment when the final assistant text narrates the same diff', () => {
|
||||
const appended: Msg[] = []
|
||||
const onEvent = createGatewayEventHandler(buildCtx(appended))
|
||||
|
||||
@@ -40,6 +40,22 @@ const diffSegmentBody = (msg: Msg): null | string => {
|
||||
|
||||
const hasDetails = (msg: Msg): boolean => Boolean(msg.thinking || msg.tools?.length || msg.toolTokens)
|
||||
|
||||
const textSegments = (segments: Msg[]) => segments.filter(msg => msg.role === 'assistant' && msg.kind !== 'diff').map(msg => msg.text)
|
||||
|
||||
const finalTail = (finalText: string, segments: Msg[]) => {
|
||||
let tail = finalText
|
||||
|
||||
for (const text of textSegments(segments)) {
|
||||
const trimmed = text.trim()
|
||||
|
||||
if (trimmed && tail.startsWith(trimmed)) {
|
||||
tail = tail.slice(trimmed.length).trimStart()
|
||||
}
|
||||
}
|
||||
|
||||
return tail
|
||||
}
|
||||
|
||||
export interface InterruptDeps {
|
||||
appendMessage: (msg: Msg) => void
|
||||
gw: { request: <T = unknown>(method: string, params?: Record<string, unknown>) => Promise<T> }
|
||||
@@ -294,7 +310,7 @@ class TurnController {
|
||||
recordMessageComplete(payload: { rendered?: string; reasoning?: string; text?: string }) {
|
||||
const rawText = (payload.rendered ?? payload.text ?? this.bufRef).trimStart()
|
||||
const split = splitReasoning(rawText)
|
||||
const finalText = split.text
|
||||
const finalText = finalTail(split.text, this.segmentMessages)
|
||||
const existingReasoning = this.reasoningText.trim() || String(payload.reasoning ?? '').trim()
|
||||
const savedReasoning = [existingReasoning, existingReasoning ? '' : split.reasoning].filter(Boolean).join('\n\n')
|
||||
const savedToolTokens = this.toolTokenAcc
|
||||
|
||||
Reference in New Issue
Block a user