92 lines
3.7 KiB
JavaScript
92 lines
3.7 KiB
JavaScript
const { loadConfig } = require('../src/config');
|
|
const { resolveMode } = require('../src/resolveMode');
|
|
const { MemorySessionStore, MysqlSessionStore } = require('../src/sessions');
|
|
const { BookCache } = require('../src/bookCache');
|
|
const { estimateCost } = require('../src/cost');
|
|
const { memoryStorage } = require('./fixture');
|
|
|
|
describe('resolveMode', () => {
|
|
const base = { tokenCount: 1000, threshold: 60000, premiumPlans: ['premium'], plan: '', style: 'default' };
|
|
|
|
it('follows the auto policy', () => {
|
|
expect(resolveMode({ ...base, override: 'full' })).toEqual({ mode: 'FULL_CONTEXT', reason: 'override' });
|
|
expect(resolveMode({ ...base, override: 'hybrid', tokenCount: 10 })).toEqual({ mode: 'HYBRID_AGENTIC', reason: 'override' });
|
|
expect(resolveMode({ ...base, tokenCount: 60001 })).toEqual({ mode: 'HYBRID_AGENTIC', reason: 'over_token_threshold' });
|
|
expect(resolveMode({ ...base, tokenCount: 60000, plan: 'premium' })).toEqual({ mode: 'FULL_CONTEXT', reason: 'premium_plan' });
|
|
expect(resolveMode({ ...base, style: 'study' })).toEqual({ mode: 'FULL_CONTEXT', reason: 'study_style' });
|
|
expect(resolveMode(base)).toEqual({ mode: 'HYBRID_AGENTIC', reason: 'default_hybrid' });
|
|
});
|
|
});
|
|
|
|
describe('chat config', () => {
|
|
it('defaults cache settings for a local run', () => {
|
|
const config = loadConfig({}, { local: true });
|
|
expect(config.cacheTtl).toBe('5m');
|
|
expect(config.cacheMinTokens).toBe(4096);
|
|
expect(config.autoFullContextMaxTokens).toBe(60000);
|
|
expect(config.agentMaxIterations).toBe(4);
|
|
expect(config.priceTable).toEqual({});
|
|
});
|
|
});
|
|
|
|
describe('sessions and book cache', () => {
|
|
it('stores a session in memory', async () => {
|
|
const store = new MemorySessionStore();
|
|
const created = await store.create({ bookId: 3, mode: 'HYBRID_AGENTIC', channel: 'chat' });
|
|
created.history = [{ role: 'user', text: 'Hi' }];
|
|
await store.save(created);
|
|
const loaded = await store.get(created.sessionId);
|
|
expect(loaded.history).toHaveLength(1);
|
|
expect(loaded.mode).toBe('HYBRID_AGENTIC');
|
|
});
|
|
|
|
it('maps a mysql session row', async () => {
|
|
const pool = {
|
|
async query(sql) {
|
|
if (String(sql).includes('SELECT')) {
|
|
return [[{
|
|
session_id: 's1',
|
|
book_id: '3',
|
|
user_id: 4,
|
|
mode: 'FULL_CONTEXT',
|
|
channel: 'voice',
|
|
style: 'study',
|
|
plan: 'premium',
|
|
history: [{ role: 'user', text: 'Hello' }],
|
|
rolling_summary: '',
|
|
last_cache_touch_at: null,
|
|
cumulative_usage: { inputTokens: 1, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0, toolCalls: 0, llmCalls: 0, estimatedCostUsd: 0 },
|
|
keepalive_count: 0,
|
|
created_at: new Date('2026-01-01T00:00:00Z'),
|
|
}]];
|
|
}
|
|
return [{ affectedRows: 1 }];
|
|
},
|
|
};
|
|
const store = new MysqlSessionStore(pool);
|
|
await store.ensure();
|
|
const session = await store.get('s1');
|
|
expect(session.bookId).toBe('3');
|
|
expect(session.history[0].text).toBe('Hello');
|
|
});
|
|
|
|
it('loads each book once', async () => {
|
|
const storage = memoryStorage('3');
|
|
const cache = new BookCache(storage, 2);
|
|
const first = await cache.load('3', 'v1');
|
|
const reads = storage.reads();
|
|
const second = await cache.load('3', 'v1');
|
|
expect(second).toBe(first);
|
|
expect(storage.reads()).toBe(reads);
|
|
});
|
|
});
|
|
|
|
describe('cost', () => {
|
|
it('prices tokens from the table', () => {
|
|
const cost = estimateCost('m', { inputTokens: 1000, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0 }, {
|
|
m: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
|
|
});
|
|
expect(cost).toBe(3);
|
|
});
|
|
});
|