Files
hermes-desktop/tests/server/run-chat-tool-result-context.test.ts
toor 01d9e301fc
Build / build (push) Canceled after 0s
Playwright / browser (push) Canceled after 0s
initialize Electron desktop app and remove unused files
2026-10-25 01:09:01 +08:00

94 lines
3.2 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest'
const addMessageMock = vi.fn()
const getSessionDetailMock = vi.fn()
vi.mock('../../packages/server/src/db/hermes/session-store', () => ({
addMessage: addMessageMock,
getSessionDetail: getSessionDetailMock,
}))
vi.mock('../../packages/server/src/db/hermes/compression-snapshot', () => ({
getCompressionSnapshot: vi.fn(() => null),
}))
vi.mock('../../packages/server/src/services/logger', () => ({
logger: {
info: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
debug: vi.fn(),
},
}))
describe('Bridge tool result context projection', () => {
beforeEach(() => {
addMessageMock.mockReset()
getSessionDetailMock.mockReset()
})
it('keeps the complete result in memory and persistence while context is bounded', async () => {
const completeToolResult = `HEAD-${'x'.repeat(70_000)}-TAIL`
const state: any = {
messages: [],
bridgePendingTools: [{
id: 'tool-call-1',
name: 'session_get',
arguments: '{}',
startedAt: Date.now(),
}],
}
const { recordBridgeToolCompleted } = await import(
'../../packages/server/src/services/hermes/run-chat/bridge-message'
)
const { truncateToolResultForContext } = await import(
'../../packages/server/src/lib/tool-result-context'
)
const completed = recordBridgeToolCompleted(
state,
'session-1',
'run-1',
'session_get',
{ tool_call_id: 'tool-call-1', result: completeToolResult },
)
expect(completed.output).toBe(completeToolResult)
expect(state.messages[0].content).toBe(completeToolResult)
expect(addMessageMock).toHaveBeenCalledWith(expect.objectContaining({
role: 'tool',
content: completeToolResult,
}))
expect(truncateToolResultForContext(completeToolResult)).toHaveLength(5_500)
})
it('bounds Bridge context tokens without changing the default Coding Agent estimate', async () => {
const completeToolResult = `HEAD-${'x'.repeat(70_000)}-TAIL`
getSessionDetailMock.mockReturnValue({
messages: [{ role: 'tool', content: completeToolResult }],
})
const { countTokens } = await import('../../packages/server/src/lib/context-compressor')
const { truncateToolResultForContext } = await import(
'../../packages/server/src/lib/tool-result-context'
)
const { calcAndUpdateUsage } = await import(
'../../packages/server/src/services/hermes/run-chat/usage'
)
const makeState = () => ({ messages: [], isWorking: false, events: [], queue: [] }) as any
const bridgeUsage = await calcAndUpdateUsage(
'session-1',
makeState(),
vi.fn(),
{ truncateToolResultsForContext: true },
)
const defaultUsage = await calcAndUpdateUsage('session-1', makeState(), vi.fn())
expect(bridgeUsage.outputTokens).toBe(countTokens(completeToolResult))
expect(bridgeUsage.contextOutputTokens).toBe(countTokens(truncateToolResultForContext(completeToolResult)))
expect(defaultUsage.outputTokens).toBe(countTokens(completeToolResult))
expect(defaultUsage.contextOutputTokens).toBeUndefined()
expect(bridgeUsage.outputTokens).toBeGreaterThan(bridgeUsage.contextOutputTokens || 0)
})
})