ktx/packages/context/src/llm/local-config.test.ts
2026-05-10 23:51:24 +02:00

127 lines
4.2 KiB
TypeScript

import { describe, expect, it, vi } from 'vitest';
import {
buildDefaultKtxProjectConfig,
type KtxProjectEmbeddingConfig,
type KtxProjectLlmConfig,
} from '../project/config.js';
import {
createLocalKtxEmbeddingProviderFromConfig,
createLocalKtxLlmProviderFromConfig,
resolveLocalKtxEmbeddingConfig,
resolveLocalKtxLlmConfig,
} from './local-config.js';
describe('local KTX LLM config', () => {
it('resolves env and file references into a KtxLlmConfig', () => {
const config: KtxProjectLlmConfig = {
provider: {
backend: 'gateway',
gateway: { api_key: 'env:AI_GATEWAY_API_KEY', base_url: 'https://gateway.example/v1' }, // pragma: allowlist secret
},
models: { default: 'env:KTX_MODEL', triage: 'anthropic/claude-haiku-4-5' },
promptCaching: { enabled: false },
};
expect(
resolveLocalKtxLlmConfig(config, {
AI_GATEWAY_API_KEY: 'gateway-key', // pragma: allowlist secret
KTX_MODEL: 'anthropic/claude-sonnet-4-6',
}),
).toEqual({
backend: 'gateway',
gateway: { apiKey: 'gateway-key', baseURL: 'https://gateway.example/v1' }, // pragma: allowlist secret
modelSlots: { default: 'anthropic/claude-sonnet-4-6', triage: 'anthropic/claude-haiku-4-5' },
promptCaching: { enabled: false },
});
});
it('returns null when the local LLM backend is disabled', () => {
expect(
createLocalKtxLlmProviderFromConfig({
provider: { backend: 'none' },
models: {},
}),
).toBeNull();
});
it('constructs providers through @ktx/llm', () => {
const createKtxLlmProvider = vi.fn(() => ({ getModel: vi.fn() }) as never);
const result = createLocalKtxLlmProviderFromConfig(
{
provider: {
backend: 'anthropic',
anthropic: { api_key: 'env:ANTHROPIC_API_KEY' }, // pragma: allowlist secret
},
models: { default: 'claude-sonnet-4-6' },
},
{ env: { ANTHROPIC_API_KEY: 'sk-ant-test' }, createKtxLlmProvider }, // pragma: allowlist secret
);
expect(result).not.toBeNull();
expect(createKtxLlmProvider).toHaveBeenCalledWith({
backend: 'anthropic',
anthropic: { apiKey: 'sk-ant-test' }, // pragma: allowlist secret
modelSlots: { default: 'claude-sonnet-4-6' },
promptCaching: undefined,
});
});
it('inherits enabled prompt caching from @ktx/llm when local config omits promptCaching', () => {
const provider = createLocalKtxLlmProviderFromConfig({
provider: {
backend: 'gateway',
gateway: { base_url: 'https://gateway.example/v1' },
},
models: { default: 'anthropic/claude-sonnet-4-6' },
});
expect(provider?.promptCachingConfig()).toMatchObject({
enabled: true,
systemTtl: '1h',
toolsTtl: '1h',
historyTtl: '5m',
vertexFallbackTo5m: false,
});
});
});
describe('local KTX embedding config', () => {
it('resolves sentence-transformers config', () => {
const config: KtxProjectEmbeddingConfig = {
backend: 'sentence-transformers',
model: 'all-MiniLM-L6-v2',
dimensions: 384,
sentenceTransformers: { base_url: 'http://localhost:18081', pathPrefix: '' },
batchSize: 16,
};
expect(resolveLocalKtxEmbeddingConfig(config, {})).toEqual({
backend: 'sentence-transformers',
model: 'all-MiniLM-L6-v2',
dimensions: 384,
sentenceTransformers: { baseURL: 'http://localhost:18081', pathPrefix: '' },
batchSize: 16,
});
});
it('constructs deterministic embeddings from the default project config', () => {
const createKtxEmbeddingProvider = vi.fn(() => ({}) as never);
const provider = createLocalKtxEmbeddingProviderFromConfig(
buildDefaultKtxProjectConfig('warehouse').ingest.embeddings,
{ createKtxEmbeddingProvider },
);
expect(provider).not.toBeNull();
expect(createKtxEmbeddingProvider).toHaveBeenCalledWith(
expect.objectContaining({
backend: 'deterministic',
model: 'deterministic',
dimensions: 8,
}),
);
});
it('returns null when embeddings are disabled', () => {
expect(createLocalKtxEmbeddingProviderFromConfig({ backend: 'none', dimensions: 8 })).toBeNull();
});
});