mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-06 18:57:21 +08:00
24 files, -319 LoC. Behaviour preserved, 369/369 tests green. - hermes-ink caches: shared lruEvict helper for the four parallel LRU caches (stringWidth, wrapText, sliceAnsi, lineWidth); touch-on-read stays inlined per cache; tightened output.ts skip-slice fast path. - wheelAccel: trimmed provenance header, collapsed env parsing, ternary dispatch in computeWheelStep. - perfPane: folded ensureLogDir into once-flag, spread-with-overrides for fastPath/phases instead of full rebuilds. - env: extracted truthy() (used 4×). - virtualHeights: collapsed user/diff/slash height bumps; trail+todos estimate. - useInputHandlers: scrollIdleTimer cleanup on unmount, ?? undefined shorthand. - useMainApp: dropped dead liveTailVisible IIFE and liveProgress indirection. - appLayout, markdown, messageLine, entry: vertical rhythm, dropped narration comments, inlined one-shot vars. - fix: empty catch blocks → /* best-effort */ for no-empty lint.
117 lines
4.2 KiB
TypeScript
117 lines
4.2 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
|
|
import type { Msg } from '../types.js'
|
|
|
|
import { appendToolShelfMessage, canHoldToolShelf, isTodoDone, mergeToolShelfInto } from './liveProgress.js'
|
|
|
|
describe('isTodoDone', () => {
|
|
it('only treats non-empty all-completed/cancelled lists as done', () => {
|
|
expect(isTodoDone([])).toBe(false)
|
|
expect(isTodoDone([{ content: 'x', id: 'x', status: 'completed' }])).toBe(true)
|
|
expect(isTodoDone([{ content: 'x', id: 'x', status: 'in_progress' }])).toBe(false)
|
|
expect(
|
|
isTodoDone([
|
|
{ content: 'x', id: 'x', status: 'completed' },
|
|
{ content: 'y', id: 'y', status: 'cancelled' }
|
|
])
|
|
).toBe(true)
|
|
})
|
|
})
|
|
|
|
describe('tool shelf helpers', () => {
|
|
it('recognizes contextual thinking shelves as holders', () => {
|
|
expect(canHoldToolShelf({ kind: 'trail', role: 'system', text: '', thinking: 'plan' })).toBe(true)
|
|
expect(canHoldToolShelf({ kind: 'trail', role: 'system', text: '', tools: ['one ✓'] })).toBe(true)
|
|
expect(canHoldToolShelf({ role: 'assistant', text: 'done' })).toBe(false)
|
|
})
|
|
|
|
it('merges source rows into an existing shelf', () => {
|
|
expect(
|
|
mergeToolShelfInto(
|
|
{ kind: 'trail', role: 'system', text: '', thinking: 'plan', tools: ['one ✓'] },
|
|
{ kind: 'trail', role: 'system', text: '', tools: ['two ✓'] }
|
|
)
|
|
).toEqual({ kind: 'trail', role: 'system', text: '', thinking: 'plan', tools: ['one ✓', 'two ✓'] })
|
|
})
|
|
})
|
|
|
|
describe('appendToolShelfMessage', () => {
|
|
it('merges adjacent tool shelves into one contextual shelf', () => {
|
|
const merged = appendToolShelfMessage([{ kind: 'trail', role: 'system', text: '', tools: ['one ✓'] }], {
|
|
kind: 'trail',
|
|
role: 'system',
|
|
text: '',
|
|
tools: ['two ✓']
|
|
})
|
|
|
|
expect(merged).toEqual([{ kind: 'trail', role: 'system', text: '', tools: ['one ✓', 'two ✓'] }])
|
|
})
|
|
|
|
it('adds tools to the nearest contextual thinking shelf', () => {
|
|
const merged = appendToolShelfMessage(
|
|
[{ kind: 'trail', role: 'system', text: '', thinking: 'plan', tools: ['one ✓'] }],
|
|
{ kind: 'trail', role: 'system', text: '', tools: ['two ✓'] }
|
|
)
|
|
|
|
expect(merged).toEqual([{ kind: 'trail', role: 'system', text: '', thinking: 'plan', tools: ['one ✓', 'two ✓'] }])
|
|
})
|
|
|
|
it('merges through intervening thinking-only rows back into the nearest holder', () => {
|
|
const prev: Msg[] = [
|
|
{ kind: 'trail', role: 'system', text: '', thinking: 'plan', tools: ['one ✓'] },
|
|
{ kind: 'trail', role: 'system', text: '', thinking: 'more plan' }
|
|
]
|
|
|
|
const merged = appendToolShelfMessage(prev, {
|
|
kind: 'trail',
|
|
role: 'system',
|
|
text: '',
|
|
tools: ['two ✓']
|
|
})
|
|
|
|
expect(merged).toHaveLength(2)
|
|
expect(merged[0]).toEqual({
|
|
kind: 'trail',
|
|
role: 'system',
|
|
text: '',
|
|
thinking: 'plan',
|
|
tools: ['one ✓', 'two ✓']
|
|
})
|
|
expect(merged[1]).toEqual({ kind: 'trail', role: 'system', text: '', thinking: 'more plan' })
|
|
})
|
|
|
|
it('collapses a chronological thinking/tool/thinking/tool stream into one shelf', () => {
|
|
const events: Msg[] = [
|
|
{ kind: 'trail', role: 'system', text: '', thinking: 'plan' },
|
|
{ kind: 'trail', role: 'system', text: '', tools: ['one ✓'] },
|
|
{ kind: 'trail', role: 'system', text: '', thinking: 'more plan' },
|
|
{ kind: 'trail', role: 'system', text: '', tools: ['two ✓'] },
|
|
{ kind: 'trail', role: 'system', text: '', tools: ['three ✓'] }
|
|
]
|
|
|
|
const reduced = events.reduce<Msg[]>((acc, msg) => appendToolShelfMessage(acc, msg), [])
|
|
|
|
expect(reduced).toHaveLength(2)
|
|
expect(reduced[0]).toEqual({
|
|
kind: 'trail',
|
|
role: 'system',
|
|
text: '',
|
|
thinking: 'plan',
|
|
tools: ['one ✓', 'two ✓', 'three ✓']
|
|
})
|
|
expect(reduced[1]).toEqual({ kind: 'trail', role: 'system', text: '', thinking: 'more plan' })
|
|
})
|
|
|
|
it('starts a new shelf across assistant text boundaries', () => {
|
|
const merged = appendToolShelfMessage(
|
|
[
|
|
{ kind: 'trail', role: 'system', text: '', tools: ['one ✓'] },
|
|
{ role: 'assistant', text: 'done' }
|
|
],
|
|
{ kind: 'trail', role: 'system', text: '', tools: ['two ✓'] }
|
|
)
|
|
|
|
expect(merged).toHaveLength(3)
|
|
})
|
|
})
|