mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-08 13:12:08 +00:00
145 lines
3.8 KiB
TypeScript
145 lines
3.8 KiB
TypeScript
import { mkdtempSync, readFileSync, rmSync } from 'node:fs'
|
|
import { tmpdir } from 'node:os'
|
|
import { join } from 'node:path'
|
|
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
import { turnController } from '../app/turnController.js'
|
|
import { getTurnState, resetTurnState } from '../app/turnStore.js'
|
|
import { patchUiState, resetUiState } from '../app/uiStore.js'
|
|
import {
|
|
hydrateLiveSessionInflight,
|
|
liveSessionInflightMessages,
|
|
scheduleResumeScrollToBottom,
|
|
writeActiveSessionFile
|
|
} from '../app/useSessionLifecycle.js'
|
|
|
|
describe('writeActiveSessionFile', () => {
|
|
let dir = ''
|
|
|
|
afterEach(() => {
|
|
if (dir) {
|
|
rmSync(dir, { force: true, recursive: true })
|
|
dir = ''
|
|
}
|
|
})
|
|
|
|
it('writes the actual resumed session id for the shell exit summary', () => {
|
|
dir = mkdtempSync(join(tmpdir(), 'hermes-tui-active-'))
|
|
const path = join(dir, 'active.json')
|
|
|
|
writeActiveSessionFile('actual_session', path)
|
|
|
|
expect(JSON.parse(readFileSync(path, 'utf8'))).toEqual({ session_id: 'actual_session' })
|
|
})
|
|
})
|
|
|
|
describe('live session activation in-flight state', () => {
|
|
beforeEach(() => {
|
|
resetUiState()
|
|
resetTurnState()
|
|
turnController.fullReset()
|
|
patchUiState({ streaming: true })
|
|
})
|
|
|
|
it('keeps the in-flight user prompt in history and hydrates partial assistant text', () => {
|
|
const inflight = { assistant: 'partial answer', streaming: true, user: 'write a long answer' }
|
|
|
|
expect(liveSessionInflightMessages(inflight)).toEqual([{ role: 'user', text: 'write a long answer' }])
|
|
|
|
hydrateLiveSessionInflight(inflight)
|
|
|
|
expect(turnController.bufRef).toBe('partial answer')
|
|
expect(getTurnState().streaming).toBe('partial answer')
|
|
})
|
|
|
|
it('ignores empty in-flight payloads', () => {
|
|
expect(liveSessionInflightMessages({ assistant: '', streaming: false, user: ' ' })).toEqual([])
|
|
|
|
hydrateLiveSessionInflight({ assistant: '', streaming: false, user: '' })
|
|
|
|
expect(turnController.bufRef).toBe('')
|
|
expect(getTurnState().streaming).toBe('')
|
|
})
|
|
})
|
|
|
|
describe('resume scroll settle', () => {
|
|
afterEach(() => {
|
|
vi.useRealTimers()
|
|
})
|
|
|
|
it('re-snaps while sticky and stops when the user scrolls away', () => {
|
|
vi.useFakeTimers()
|
|
let sticky = true
|
|
let lastManualScrollAt = 0
|
|
const scrollToBottom = vi.fn()
|
|
const cancel = scheduleResumeScrollToBottom(
|
|
{
|
|
current: {
|
|
getLastManualScrollAt: () => lastManualScrollAt,
|
|
isSticky: () => sticky,
|
|
scrollToBottom
|
|
}
|
|
} as any,
|
|
[0, 80, 240]
|
|
)
|
|
|
|
vi.advanceTimersByTime(0)
|
|
expect(scrollToBottom).toHaveBeenCalledTimes(1)
|
|
|
|
vi.advanceTimersByTime(80)
|
|
expect(scrollToBottom).toHaveBeenCalledTimes(2)
|
|
|
|
sticky = false
|
|
lastManualScrollAt = Date.now() + 1
|
|
vi.advanceTimersByTime(160)
|
|
expect(scrollToBottom).toHaveBeenCalledTimes(2)
|
|
|
|
cancel()
|
|
})
|
|
|
|
it('cancels pending resume snaps', () => {
|
|
vi.useFakeTimers()
|
|
const scrollToBottom = vi.fn()
|
|
const cancel = scheduleResumeScrollToBottom(
|
|
{
|
|
current: {
|
|
getLastManualScrollAt: () => 0,
|
|
isSticky: () => true,
|
|
scrollToBottom
|
|
}
|
|
} as any,
|
|
[20]
|
|
)
|
|
|
|
cancel()
|
|
vi.advanceTimersByTime(20)
|
|
|
|
expect(scrollToBottom).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('keeps the immediate resume snap even before sticky state settles', () => {
|
|
vi.useFakeTimers()
|
|
let sticky = false
|
|
const scrollToBottom = vi.fn()
|
|
const cancel = scheduleResumeScrollToBottom(
|
|
{
|
|
current: {
|
|
getLastManualScrollAt: () => 0,
|
|
isSticky: () => sticky,
|
|
scrollToBottom
|
|
}
|
|
} as any,
|
|
[0, 80]
|
|
)
|
|
|
|
vi.advanceTimersByTime(0)
|
|
expect(scrollToBottom).toHaveBeenCalledTimes(1)
|
|
|
|
vi.advanceTimersByTime(80)
|
|
expect(scrollToBottom).toHaveBeenCalledTimes(1)
|
|
|
|
sticky = true
|
|
cancel()
|
|
})
|
|
})
|