Files
orca/src/shared/muse-session-log.test.ts
T

142 lines
5.3 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it } from 'vitest'
import { appendFileSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import {
createMuseSessionLogState,
findMuseSessionLogPath,
readMusePendingUserInput
} from './muse-session-log'
const SESSION_ID = '01a0caa3-0e77-7d41-bad7-46283a45633d'
const PROMPT_ID = '01a0caa3-a25a-7810-8229-4de04b2e7ca3'
const QUESTION = {
id: 'fav_color',
header: 'Color',
question: 'What is your favorite color?',
options: [{ label: 'Blue' }, { label: 'Green' }, { label: 'Red' }]
}
function logLine(event: Record<string, unknown>): string {
return `${JSON.stringify({
schema_version: 1,
stream: { kind: 'session', id: SESSION_ID },
record_type: 'event',
payload_type: 'runtime.session',
payload: { kind: 'run', run_id: 'fdada6f1-d403-41d8-b610-52f1d8489334', event }
})}\n`
}
const requested = (promptId = PROMPT_ID): string =>
logLine({
kind: 'user_input_prompt_requested',
prompt_id: promptId,
tool_name: 'request_user_input',
questions: [QUESTION]
})
const settled = (promptId = PROMPT_ID): string =>
logLine({ kind: 'user_input_prompt_settled', prompt_id: promptId, outcome: 'answered' })
function sessionShard(): string[] {
const date = new Date('2026-09-22T19:41:18.839Z')
return [
String(date.getFullYear()),
String(date.getMonth() + 1).padStart(2, '0'),
String(date.getDate()).padStart(2, '0')
]
}
describe('muse session log', () => {
let sessionsDir: string
let logPath: string
beforeEach(() => {
sessionsDir = mkdtempSync(join(tmpdir(), 'muse-session-log-'))
const dir = join(sessionsDir, ...sessionShard(), SESSION_ID)
mkdirSync(dir, { recursive: true })
logPath = join(dir, 'session.jsonl')
})
afterEach(() => {
rmSync(sessionsDir, { recursive: true, force: true })
})
it('finds the log in the date shard named by the UUIDv7 timestamp', () => {
writeFileSync(logPath, '')
expect(findMuseSessionLogPath(SESSION_ID, sessionsDir)).toBe(logPath)
})
it('returns undefined for a missing log or a non-v7 session id', () => {
expect(findMuseSessionLogPath(SESSION_ID, sessionsDir)).toBeUndefined()
const nonV7 = '01a0caa3-0e77-4d41-bad7-46283a45633d'
const dir = join(sessionsDir, ...sessionShard(), nonV7)
mkdirSync(dir, { recursive: true })
writeFileSync(join(dir, 'session.jsonl'), '')
expect(findMuseSessionLogPath(nonV7, sessionsDir)).toBeUndefined()
})
it('reads prompts batched inside a retained_frame', () => {
const frame = (line: string): string =>
`${JSON.stringify({ record_type: 'retained_frame', children: [{ record_json: line.trim() }] })}\n`
writeFileSync(logPath, frame(requested()))
const log = createMuseSessionLogState(SESSION_ID)
expect(readMusePendingUserInput(log, undefined, sessionsDir)?.promptId).toBe(PROMPT_ID)
appendFileSync(logPath, frame(settled()))
expect(readMusePendingUserInput(log, undefined, sessionsDir)).toBeUndefined()
})
it('ignores a prompt left open by an earlier run', () => {
writeFileSync(logPath, requested())
const log = createMuseSessionLogState(SESSION_ID)
expect(
readMusePendingUserInput(log, 'fdada6f1-d403-41d8-b610-52f1d8489334', sessionsDir)?.promptId
).toBe(PROMPT_ID)
expect(
readMusePendingUserInput(log, '11111111-2222-4333-8444-555555555555', sessionsDir)
).toBeUndefined()
})
it('returns the open prompt and clears it once settled', () => {
writeFileSync(logPath, requested())
const log = createMuseSessionLogState(SESSION_ID)
expect(readMusePendingUserInput(log, undefined, sessionsDir)).toEqual({
promptId: PROMPT_ID,
runId: 'fdada6f1-d403-41d8-b610-52f1d8489334',
questions: [QUESTION]
})
// Re-reading with no new bytes keeps the prompt pending.
expect(readMusePendingUserInput(log, undefined, sessionsDir)?.promptId).toBe(PROMPT_ID)
appendFileSync(logPath, settled())
expect(readMusePendingUserInput(log, undefined, sessionsDir)).toBeUndefined()
})
it('holds a partial trailing line until it is completed', () => {
const line = requested()
writeFileSync(logPath, line.slice(0, 40))
const log = createMuseSessionLogState(SESSION_ID)
expect(readMusePendingUserInput(log, undefined, sessionsDir)).toBeUndefined()
appendFileSync(logPath, line.slice(40))
expect(readMusePendingUserInput(log, undefined, sessionsDir)?.questions).toEqual([QUESTION])
})
it('reports the newest of several open prompts', () => {
const second = '01a0caa4-0000-7000-8000-000000000001'
writeFileSync(logPath, `${requested()}${requested(second)}`)
const log = createMuseSessionLogState(SESSION_ID)
expect(readMusePendingUserInput(log, undefined, sessionsDir)?.promptId).toBe(second)
appendFileSync(logPath, settled(second))
expect(readMusePendingUserInput(log, undefined, sessionsDir)?.promptId).toBe(PROMPT_ID)
})
it('locates a log created after the first read', () => {
const log = createMuseSessionLogState(SESSION_ID)
expect(readMusePendingUserInput(log, undefined, sessionsDir)).toBeUndefined()
writeFileSync(logPath, requested())
expect(readMusePendingUserInput(log, undefined, sessionsDir)?.promptId).toBe(PROMPT_ID)
})
})