Files
Hermes-ui/tests/server/sessions-db.test.ts
T
ekko fd7071b75d fix: fallback title from preview when session has no explicit title
SQLite path was returning null title for sessions without an explicit
title, while the CLI path derives it from the first user message.
Now uses the preview (first user message content) as title fallback,
matching the original CLI behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-18 08:53:45 +08:00

126 lines
3.7 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest'
const allMock = vi.fn()
const prepareMock = vi.fn(() => ({ all: allMock }))
const closeMock = vi.fn()
const databaseSyncMock = vi.fn(() => ({ prepare: prepareMock, close: closeMock }))
const getActiveProfileDirMock = vi.fn(() => '/tmp/hermes-profile')
vi.mock('node:sqlite', () => ({
DatabaseSync: databaseSyncMock,
}))
vi.mock('../../packages/server/src/services/hermes/hermes-profile', () => ({
getActiveProfileDir: getActiveProfileDirMock,
}))
describe('session DB summaries', () => {
beforeEach(() => {
vi.resetModules()
allMock.mockReset()
prepareMock.mockClear()
closeMock.mockClear()
databaseSyncMock.mockClear()
getActiveProfileDirMock.mockReset()
getActiveProfileDirMock.mockReturnValue('/tmp/hermes-profile')
})
it('queries sqlite for lightweight session summaries', async () => {
allMock.mockReturnValue([
{
id: 's1',
source: 'cli',
user_id: '',
model: 'openai/gpt-5.4',
title: 'Named session',
started_at: 1710000000,
ended_at: null,
end_reason: '',
message_count: 3,
tool_call_count: 1,
input_tokens: 10,
output_tokens: 20,
cache_read_tokens: 0,
cache_write_tokens: 0,
reasoning_tokens: 0,
billing_provider: 'openrouter',
estimated_cost_usd: 0.01,
actual_cost_usd: null,
cost_status: 'estimated',
preview: 'hello world',
last_active: 1710000005,
},
])
const mod = await import('../../packages/server/src/services/hermes/sessions-db')
const rows = await mod.listSessionSummaries(undefined, 50)
expect(databaseSyncMock).toHaveBeenCalledWith('/tmp/hermes-profile/state.db', { open: true, readOnly: true })
expect(prepareMock).toHaveBeenCalledWith(expect.stringContaining("AND s.source != 'tool'"))
expect(allMock).toHaveBeenCalledWith(50)
expect(closeMock).toHaveBeenCalled()
expect(rows).toEqual([
{
id: 's1',
source: 'cli',
user_id: null,
model: 'openai/gpt-5.4',
title: 'Named session',
started_at: 1710000000,
ended_at: null,
end_reason: null,
message_count: 3,
tool_call_count: 1,
input_tokens: 10,
output_tokens: 20,
cache_read_tokens: 0,
cache_write_tokens: 0,
reasoning_tokens: 0,
billing_provider: 'openrouter',
estimated_cost_usd: 0.01,
actual_cost_usd: null,
cost_status: 'estimated',
preview: 'hello world',
last_active: 1710000005,
},
])
})
it('adds source filter and falls back last_active to started_at', async () => {
allMock.mockReturnValue([
{
id: 's2',
source: 'telegram',
user_id: '',
model: 'openai/gpt-5.4',
title: '',
started_at: 1710000100,
ended_at: null,
end_reason: '',
message_count: 1,
tool_call_count: 0,
input_tokens: 4,
output_tokens: 5,
cache_read_tokens: 0,
cache_write_tokens: 0,
reasoning_tokens: 0,
billing_provider: '',
estimated_cost_usd: 0,
actual_cost_usd: null,
cost_status: '',
preview: 'preview text',
last_active: null,
},
])
const mod = await import('../../packages/server/src/services/hermes/sessions-db')
const rows = await mod.listSessionSummaries('telegram', 2)
expect(prepareMock).toHaveBeenCalledWith(expect.stringContaining('AND s.source = ?'))
expect(allMock).toHaveBeenCalledWith('telegram', 2)
expect(rows[0].last_active).toBe(1710000100)
expect(rows[0].source).toBe('telegram')
expect(rows[0].title).toBe('preview text')
})
})