mirror of
https://github.com/EKKOLearnAI/hermes-web-ui.git
synced 2026-05-27 14:30:18 +00:00
30715c45cc
- Add getSessionDetailFromDbWithProfile to query session details from specific profile's state.db - Record usage for group chat agent runs with agent's own profile to roomId - Update context compression to use agent's profile instead of active profile - Add profile parameter to BuildContextInput and GatewayCaller.summarize interfaces - Add profile field to updateUsage calls in proxy-handler for single chat runs - Fix SessionDeleter to clean up gc_session_profiles after successful session deletion - Fix tests to match current logic and skip FTS5-dependent tests This allows multiple agents with different profiles in the same group chat to correctly track their usage separately.
125 lines
5.1 KiB
TypeScript
125 lines
5.1 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
const listConversationSummariesFromDbMock = vi.fn()
|
|
const getConversationDetailFromDbMock = vi.fn()
|
|
const listConversationSummariesMock = vi.fn()
|
|
const getConversationDetailMock = vi.fn()
|
|
const getSessionDetailFromDbMock = vi.fn()
|
|
const getSessionMock = vi.fn()
|
|
const getGroupChatServerMock = vi.fn()
|
|
const loggerWarnMock = vi.fn()
|
|
|
|
vi.mock('../../packages/server/src/db/hermes/conversations-db', () => ({
|
|
listConversationSummariesFromDb: listConversationSummariesFromDbMock,
|
|
getConversationDetailFromDb: getConversationDetailFromDbMock,
|
|
}))
|
|
|
|
vi.mock('../../packages/server/src/services/hermes/conversations', () => ({
|
|
listConversationSummaries: listConversationSummariesMock,
|
|
getConversationDetail: getConversationDetailMock,
|
|
}))
|
|
|
|
vi.mock('../../packages/server/src/services/logger', () => ({
|
|
logger: {
|
|
warn: loggerWarnMock,
|
|
error: vi.fn(),
|
|
},
|
|
}))
|
|
|
|
vi.mock('../../packages/server/src/services/hermes/hermes-cli', () => ({
|
|
listSessions: vi.fn(),
|
|
getSession: getSessionMock,
|
|
deleteSession: vi.fn(),
|
|
renameSession: vi.fn(),
|
|
}))
|
|
|
|
vi.mock('../../packages/server/src/db/hermes/sessions-db', () => ({
|
|
listSessionSummaries: vi.fn(),
|
|
searchSessionSummaries: vi.fn(),
|
|
getSessionDetailFromDb: getSessionDetailFromDbMock,
|
|
}))
|
|
|
|
// Mock useLocalSessionStore to return false so we test the CLI path
|
|
vi.mock('../../packages/server/src/db/hermes/session-store', () => ({
|
|
useLocalSessionStore: () => false,
|
|
}))
|
|
|
|
vi.mock('../../packages/server/src/db/hermes/usage-store', () => ({
|
|
deleteUsage: vi.fn(),
|
|
getUsage: vi.fn(),
|
|
getUsageBatch: vi.fn(),
|
|
}))
|
|
|
|
vi.mock('../../packages/server/src/routes/hermes/group-chat', () => ({
|
|
getGroupChatServer: getGroupChatServerMock,
|
|
}))
|
|
|
|
vi.mock('../../packages/server/src/services/hermes/model-context', () => ({
|
|
getModelContextLength: vi.fn(),
|
|
}))
|
|
|
|
describe('session conversations controller', () => {
|
|
beforeEach(() => {
|
|
vi.resetModules()
|
|
listConversationSummariesFromDbMock.mockReset()
|
|
getConversationDetailFromDbMock.mockReset()
|
|
listConversationSummariesMock.mockReset()
|
|
getConversationDetailMock.mockReset()
|
|
getSessionDetailFromDbMock.mockReset()
|
|
getSessionMock.mockReset()
|
|
getGroupChatServerMock.mockReset()
|
|
getGroupChatServerMock.mockReturnValue(null)
|
|
loggerWarnMock.mockReset()
|
|
})
|
|
|
|
it('prefers the DB-backed conversations summary path', async () => {
|
|
listConversationSummariesFromDbMock.mockResolvedValue([{ id: 'db-conversation' }])
|
|
|
|
const mod = await import('../../packages/server/src/controllers/hermes/sessions')
|
|
const ctx: any = { query: { humanOnly: 'true', limit: '5' }, body: null }
|
|
await mod.listConversations(ctx)
|
|
|
|
expect(listConversationSummariesFromDbMock).toHaveBeenCalledWith({ source: undefined, humanOnly: true, limit: 5 })
|
|
expect(listConversationSummariesMock).not.toHaveBeenCalled()
|
|
expect(ctx.body).toEqual({ sessions: [{ id: 'db-conversation' }] })
|
|
})
|
|
|
|
it('falls back to the CLI-export conversations summary path when the DB query fails', async () => {
|
|
listConversationSummariesFromDbMock.mockRejectedValue(new Error('db unavailable'))
|
|
listConversationSummariesMock.mockResolvedValue([{ id: 'fallback-conversation' }])
|
|
|
|
const mod = await import('../../packages/server/src/controllers/hermes/sessions')
|
|
const ctx: any = { query: { humanOnly: 'false' }, body: null }
|
|
await mod.listConversations(ctx)
|
|
|
|
expect(loggerWarnMock).toHaveBeenCalled()
|
|
expect(listConversationSummariesMock).toHaveBeenCalledWith({ source: undefined, humanOnly: false, limit: undefined })
|
|
expect(ctx.body).toEqual({ sessions: [{ id: 'fallback-conversation' }] })
|
|
})
|
|
|
|
it('prefers the DB-backed conversation detail path', async () => {
|
|
getConversationDetailFromDbMock.mockResolvedValue({ session_id: 'root', messages: [], visible_count: 0, thread_session_count: 1 })
|
|
|
|
const mod = await import('../../packages/server/src/controllers/hermes/sessions')
|
|
const ctx: any = { params: { id: 'root' }, query: { humanOnly: 'true' }, body: null }
|
|
await mod.getConversationMessages(ctx)
|
|
|
|
expect(getConversationDetailFromDbMock).toHaveBeenCalledWith('root', { source: undefined, humanOnly: true })
|
|
expect(getConversationDetailMock).not.toHaveBeenCalled()
|
|
expect(ctx.body).toEqual({ session_id: 'root', messages: [], visible_count: 0, thread_session_count: 1 })
|
|
})
|
|
|
|
it('falls back to the CLI-export conversation detail path when the DB query throws', async () => {
|
|
getConversationDetailFromDbMock.mockRejectedValue(new Error('db unavailable'))
|
|
getConversationDetailMock.mockResolvedValue({ session_id: 'root', messages: [{ id: 1 }], visible_count: 1, thread_session_count: 1 })
|
|
|
|
const mod = await import('../../packages/server/src/controllers/hermes/sessions')
|
|
const ctx: any = { params: { id: 'root' }, query: { humanOnly: 'false' }, body: null }
|
|
await mod.getConversationMessages(ctx)
|
|
|
|
expect(loggerWarnMock).toHaveBeenCalled()
|
|
expect(getConversationDetailMock).toHaveBeenCalledWith('root', { source: undefined, humanOnly: false })
|
|
expect(ctx.body).toEqual({ session_id: 'root', messages: [{ id: 1 }], visible_count: 1, thread_session_count: 1 })
|
|
})
|
|
})
|