94 lines
3.2 KiB
TypeScript
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)
|
|
})
|
|
})
|