Fix bridge compression history handling (#726)

* feat(bridge): refactor compression to use DB history and add structured logging

- Extract buildDbHistory() to share message loading between buildCompressedHistory and forceCompressBridgeHistory
- forceCompressBridgeHistory now reads from local DB instead of using Python-provided messages, ensuring consistency with api_server path
- Pass sessionId to compressor for snapshot-aware compression
- Add force_compress flag to bridge chat requests
- Add bridgeLogger structured logging for compression lifecycle
- Simplify schemas, session-sync, and providers

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix bridge compression history handling

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
ekko
2026-05-14 21:02:59 +08:00
committed by GitHub
parent 7420f7aad5
commit d0f1e7d1f2
19 changed files with 576 additions and 638 deletions
+39 -49
View File
@@ -1,70 +1,60 @@
/**
* Tests for session-sync service
* Tests for the disabled Hermes session import path.
*/
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
import { getDb } from '../../packages/server/src/db/index'
import { initAllStores } from '../../packages/server/src/db/hermes/init'
import { listSessionSummaries } from '../../packages/server/src/db/hermes/sessions-db'
import { syncAllHermesSessionsOnStartup } from '../../packages/server/src/services/hermes/session-sync'
vi.mock('../../packages/server/src/db/hermes/sessions-db', () => ({
listSessionSummaries: vi.fn().mockResolvedValue([]),
getSessionDetailFromDbWithProfile: vi.fn(),
}))
function resetSessionTables(): void {
initAllStores()
const db = getDb()
if (db) {
db.exec('DELETE FROM messages')
db.exec('DELETE FROM sessions')
}
}
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
describe('session-sync', () => {
beforeEach(() => {
vi.clearAllMocks()
resetSessionTables()
let db: any = null
beforeEach(async () => {
vi.resetModules()
const { DatabaseSync } = await import('node:sqlite')
db = new DatabaseSync(':memory:')
vi.doMock('../../packages/server/src/db/index', () => ({
getDb: () => db,
getStoragePath: () => ':memory:',
}))
vi.doMock('../../packages/server/src/db/hermes/sessions-db', () => ({
listSessionSummaries: vi.fn().mockResolvedValue([]),
getSessionDetailFromDbWithProfile: vi.fn(),
}))
})
afterEach(() => {
resetSessionTables()
db?.close()
db = null
vi.doUnmock('../../packages/server/src/db/index')
vi.doUnmock('../../packages/server/src/db/hermes/sessions-db')
vi.resetModules()
})
it('should skip sync when local DB is not empty', async () => {
const db = getDb()
expect(db).not.toBeNull()
async function initTestDb() {
const { initAllStores } = await import('../../packages/server/src/db/hermes/init')
initAllStores()
}
// Insert a test session
db!.prepare(`
it('does not import Hermes sessions when local DB is not empty', async () => {
await initTestDb()
const { syncAllHermesSessionsOnStartup } = await import('../../packages/server/src/services/hermes/session-sync')
db.prepare(`
INSERT INTO sessions (id, profile, source, model, title, started_at, last_active)
VALUES ('test-session-1', 'default', 'api_server', 'gpt-4', 'Test Session', ${Date.now()}, ${Date.now()})
`).run()
VALUES ('test-session-1', 'default', 'api_server', 'gpt-4', 'Test Session', ?, ?)
`).run(Date.now(), Date.now())
// Check that session exists
const countResult = db!.prepare('SELECT COUNT(*) as count FROM sessions').get() as { count: number }
expect(countResult.count).toBe(1)
// Run sync - should skip because DB is not empty
await syncAllHermesSessionsOnStartup()
expect(vi.mocked(listSessionSummaries)).not.toHaveBeenCalled()
// Verify session still exists (no changes)
const countAfter = db!.prepare('SELECT COUNT(*) as count FROM sessions').get() as { count: number }
const countAfter = db.prepare('SELECT COUNT(*) as count FROM sessions').get() as { count: number }
expect(countAfter.count).toBe(1)
})
it('should attempt sync when local DB is empty', async () => {
const db = getDb()
expect(db).not.toBeNull()
it('does not import Hermes sessions when local DB is empty', async () => {
await initTestDb()
const { syncAllHermesSessionsOnStartup } = await import('../../packages/server/src/services/hermes/session-sync')
// Verify DB is empty
const countBefore = db!.prepare('SELECT COUNT(*) as count FROM sessions').get() as { count: number }
expect(countBefore.count).toBe(0)
// Run sync - should attempt to sync from Hermes
await expect(syncAllHermesSessionsOnStartup()).resolves.toBeUndefined()
expect(vi.mocked(listSessionSummaries)).toHaveBeenCalledWith('api_server', 10000, 'default')
const countAfter = db.prepare('SELECT COUNT(*) as count FROM sessions').get() as { count: number }
expect(countAfter.count).toBe(0)
})
})