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(); }); });