mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-29 06:31:32 +00:00
Add a first-class active-session orchestrator for the Ink TUI: - list, activate, close, and launch live process-local TUI sessions - hydrate committed and in-flight output when switching sessions - dispatch a new prompt session from the +new row with session-scoped model picks - expose a clickable live-session count in the status chrome - preserve stable row order while initially focusing the current session - support mouse hit-testing for floating orchestrator overlays - add backend and frontend regression coverage for the lifecycle and UI helpers
60 lines
2 KiB
TypeScript
60 lines
2 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 } 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, 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('')
|
|
})
|
|
})
|