Files
hermes-web-ui/tests/server/session-store-branch.test.ts
牧濑红莉栖(BOT) 0bfa9d2ed4 fix(coding-agent): 持久化会话 API 模式 (#1944)
* fix(coding-agent): persist API mode per session

* docs(chat-chain): document coding agent API mode persistence

---------

Co-authored-by: x1051445024 <你的GitHub注册邮箱>
2026-07-06 08:17:49 +08:00

123 lines
3.5 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest'
const mocks = vi.hoisted(() => {
const updateParentRun = vi.fn()
const insertSessionRun = vi.fn()
const insertMessageRun = vi.fn(() => ({ lastInsertRowid: 42 }))
const updateForkPointRun = vi.fn()
const selectSessionGet = vi.fn()
const prepare = vi.fn((sql: string) => {
if (sql.includes('UPDATE sessions SET ended_at')) return { run: updateParentRun }
if (sql.includes('UPDATE sessions SET fork_point_message_id')) return { run: updateForkPointRun }
if (sql.includes('INSERT INTO sessions')) return { run: insertSessionRun }
if (sql.includes('INSERT INTO messages')) return { run: insertMessageRun }
if (sql.includes('SELECT * FROM sessions WHERE id = ?')) return { get: selectSessionGet }
throw new Error(`unexpected SQL: ${sql}`)
})
const exec = vi.fn()
const db = { prepare, exec }
return {
updateParentRun,
insertSessionRun,
insertMessageRun,
updateForkPointRun,
selectSessionGet,
prepare,
exec,
db,
copyCompressionSnapshot: vi.fn(),
}
})
vi.mock('../../packages/server/src/db/index', () => ({
isSqliteAvailable: vi.fn(() => true),
getDb: vi.fn(() => mocks.db),
}))
vi.mock('../../packages/server/src/db/hermes/compression-snapshot', () => ({
copyCompressionSnapshot: mocks.copyCompressionSnapshot,
}))
describe('createBranchedSession', () => {
beforeEach(() => {
vi.clearAllMocks()
mocks.selectSessionGet.mockReturnValue({
id: 'child-session',
profile: 'default',
source: 'cli',
agent: 'hermes',
agent_mode: '',
agent_session_id: '',
agent_native_session_id: '',
user_id: null,
model: 'openai/gpt-5.4',
provider: 'openai-codex',
api_mode: 'chat_completions',
title: 'Forked child',
parent_session_id: 'parent-session',
fork_point_message_id: '42',
started_at: 123,
ended_at: null,
end_reason: null,
message_count: 1,
tool_call_count: 0,
input_tokens: 0,
output_tokens: 0,
cache_read_tokens: 0,
cache_write_tokens: 0,
reasoning_tokens: 0,
billing_provider: null,
estimated_cost_usd: 0,
actual_cost_usd: null,
cost_status: '',
preview: '',
last_active: 123,
workspace: '/repo',
})
})
it('copies the parent compression snapshot inside the fork transaction', async () => {
const { createBranchedSession } = await import('../../packages/server/src/db/hermes/session-store')
const result = createBranchedSession({
parent_session_id: 'parent-session',
id: 'child-session',
profile: 'default',
source: 'cli',
agent: 'hermes',
model: 'openai/gpt-5.4',
provider: 'openai-codex',
api_mode: 'chat_completions',
title: 'Forked child',
workspace: '/repo',
ended_at: 123,
last_active: 123,
messages: [
{ role: 'user', content: 'hello', timestamp: 100 },
],
})
expect(result?.id).toBe('child-session')
expect(mocks.exec).toHaveBeenNthCalledWith(1, 'BEGIN')
expect(mocks.copyCompressionSnapshot).toHaveBeenCalledWith('parent-session', 'child-session')
expect(mocks.updateForkPointRun).toHaveBeenCalledWith('42', 'child-session')
expect(mocks.exec).toHaveBeenLastCalledWith('COMMIT')
expect(mocks.insertMessageRun).toHaveBeenCalledWith(
'child-session',
'user',
'hello',
null,
null,
null,
null,
null,
100,
null,
null,
null,
null,
null,
)
})
})