mirror of
https://github.com/EKKOLearnAI/hermes-web-ui.git
synced 2026-05-25 21:40:13 +00:00
92 lines
2.7 KiB
TypeScript
92 lines
2.7 KiB
TypeScript
import { describe, expect, it, vi } from 'vitest'
|
|
import { countTokens } from '../../packages/server/src/lib/context-compressor'
|
|
import {
|
|
contextTokensWithCachedOverhead,
|
|
estimateUsageTokensFromMessages,
|
|
updateMessageContextTokenUsage,
|
|
} from '../../packages/server/src/services/hermes/run-chat/usage'
|
|
|
|
describe('run-chat usage token estimates', () => {
|
|
it('counts message content instead of serialized message payloads', () => {
|
|
const messages = [
|
|
{ role: 'user', content: 'hello from user' },
|
|
{ role: 'assistant', content: 'hello from assistant' },
|
|
]
|
|
|
|
const usage = estimateUsageTokensFromMessages(messages)
|
|
|
|
expect(usage.inputTokens).toBe(countTokens('hello from user'))
|
|
expect(usage.outputTokens).toBe(countTokens('hello from assistant'))
|
|
expect(usage.inputTokens + usage.outputTokens).toBeLessThan(countTokens(JSON.stringify(messages)))
|
|
})
|
|
|
|
it('keeps assistant tool call tokens on the output side', () => {
|
|
const messages = [
|
|
{
|
|
role: 'assistant',
|
|
content: 'calling tool',
|
|
tool_calls: [{ id: 'call_1', type: 'function', function: { name: 'lookup', arguments: '{"q":"x"}' } }],
|
|
},
|
|
]
|
|
|
|
const usage = estimateUsageTokensFromMessages(messages)
|
|
|
|
expect(usage.inputTokens).toBe(0)
|
|
expect(usage.outputTokens).toBe(countTokens('calling tool') + countTokens(String(messages[0].tool_calls || '')))
|
|
})
|
|
|
|
it('adds cached bridge fixed context when updating full context usage', () => {
|
|
const emit = vi.fn()
|
|
const state = {
|
|
messages: [],
|
|
isWorking: false,
|
|
events: [],
|
|
queue: [],
|
|
bridgeContext: { fixedContextTokens: 20_000 },
|
|
} as any
|
|
|
|
const contextTokens = updateMessageContextTokenUsage(
|
|
'session-1',
|
|
state,
|
|
emit,
|
|
1_569,
|
|
{ inputTokens: 1_200, outputTokens: 369 },
|
|
)
|
|
|
|
expect(contextTokens).toBe(21_569)
|
|
expect(state.contextTokens).toBe(21_569)
|
|
expect(emit).toHaveBeenCalledWith('usage.updated', expect.objectContaining({
|
|
session_id: 'session-1',
|
|
inputTokens: 1_200,
|
|
outputTokens: 369,
|
|
contextTokens: 21_569,
|
|
}))
|
|
})
|
|
|
|
it('falls back to message tokens when bridge fixed context is missing', () => {
|
|
const emit = vi.fn()
|
|
const state = {
|
|
messages: [],
|
|
isWorking: false,
|
|
events: [],
|
|
queue: [],
|
|
} as any
|
|
|
|
expect(contextTokensWithCachedOverhead(state, 1_569)).toBe(1_569)
|
|
|
|
const contextTokens = updateMessageContextTokenUsage(
|
|
'session-1',
|
|
state,
|
|
emit,
|
|
1_569,
|
|
{ inputTokens: 1_200, outputTokens: 369 },
|
|
)
|
|
|
|
expect(contextTokens).toBe(1_569)
|
|
expect(state.contextTokens).toBe(1_569)
|
|
expect(emit).toHaveBeenCalledWith('usage.updated', expect.objectContaining({
|
|
contextTokens: 1_569,
|
|
}))
|
|
})
|
|
})
|