From 260e4fc35a2f9f51b0dce17bc179bb5080d4d84c Mon Sep 17 00:00:00 2001 From: Andrey Avtomonov Date: Mon, 11 May 2026 10:53:58 +0200 Subject: [PATCH] feat: add managed local embeddings config marker --- packages/context/src/llm/index.ts | 2 + packages/context/src/llm/local-config.test.ts | 41 +++++++++++++++++++ packages/context/src/llm/local-config.ts | 32 +++++++++++++++ packages/context/src/package-exports.test.ts | 4 ++ 4 files changed, 79 insertions(+) diff --git a/packages/context/src/llm/index.ts b/packages/context/src/llm/index.ts index 67e94b93..c9f039b8 100644 --- a/packages/context/src/llm/index.ts +++ b/packages/context/src/llm/index.ts @@ -11,6 +11,8 @@ export { summarizeKtxLlmDebugRequest, } from './debug-request-recorder.js'; export { + MANAGED_SENTENCE_TRANSFORMERS_BASE_URL, + MANAGED_SENTENCE_TRANSFORMERS_BASE_URL_ENV, createLocalKtxEmbeddingProviderFromConfig, createLocalKtxLlmProviderFromConfig, resolveLocalKtxEmbeddingConfig, diff --git a/packages/context/src/llm/local-config.test.ts b/packages/context/src/llm/local-config.test.ts index 96292b56..ffb00b36 100644 --- a/packages/context/src/llm/local-config.test.ts +++ b/packages/context/src/llm/local-config.test.ts @@ -5,6 +5,8 @@ import { type KtxProjectLlmConfig, } from '../project/config.js'; import { + MANAGED_SENTENCE_TRANSFORMERS_BASE_URL, + MANAGED_SENTENCE_TRANSFORMERS_BASE_URL_ENV, createLocalKtxEmbeddingProviderFromConfig, createLocalKtxLlmProviderFromConfig, resolveLocalKtxEmbeddingConfig, @@ -104,6 +106,45 @@ describe('local KTX embedding config', () => { }); }); + it('resolves managed sentence-transformers config from the CLI-provided daemon URL', () => { + const config: KtxProjectEmbeddingConfig = { + backend: 'sentence-transformers', + model: 'all-MiniLM-L6-v2', + dimensions: 384, + sentenceTransformers: { + base_url: MANAGED_SENTENCE_TRANSFORMERS_BASE_URL, + pathPrefix: '', + }, + batchSize: 32, + }; + + expect( + resolveLocalKtxEmbeddingConfig(config, { + [MANAGED_SENTENCE_TRANSFORMERS_BASE_URL_ENV]: 'http://127.0.0.1:61234', + }), + ).toEqual({ + backend: 'sentence-transformers', + model: 'all-MiniLM-L6-v2', + dimensions: 384, + sentenceTransformers: { baseURL: 'http://127.0.0.1:61234', pathPrefix: '' }, + batchSize: 32, + }); + }); + + it('returns null for managed sentence-transformers when no daemon URL is available', () => { + const config: KtxProjectEmbeddingConfig = { + backend: 'sentence-transformers', + model: 'all-MiniLM-L6-v2', + dimensions: 384, + sentenceTransformers: { + base_url: MANAGED_SENTENCE_TRANSFORMERS_BASE_URL, + pathPrefix: '', + }, + }; + + expect(resolveLocalKtxEmbeddingConfig(config, {})).toBeNull(); + }); + it('constructs deterministic embeddings from the default project config', () => { const createKtxEmbeddingProvider = vi.fn(() => ({}) as never); const provider = createLocalKtxEmbeddingProviderFromConfig( diff --git a/packages/context/src/llm/local-config.ts b/packages/context/src/llm/local-config.ts index f0654642..76f1905f 100644 --- a/packages/context/src/llm/local-config.ts +++ b/packages/context/src/llm/local-config.ts @@ -16,6 +16,9 @@ interface LocalConfigDeps { createKtxEmbeddingProvider?: typeof createKtxEmbeddingProvider; } +export const MANAGED_SENTENCE_TRANSFORMERS_BASE_URL = 'managed:local-embeddings'; +export const MANAGED_SENTENCE_TRANSFORMERS_BASE_URL_ENV = 'KTX_MANAGED_SENTENCE_TRANSFORMERS_BASE_URL'; + function resolveOptional(value: string | undefined, env: NodeJS.ProcessEnv): string | undefined { return resolveKtxConfigReference(value, env) || undefined; } @@ -89,6 +92,19 @@ export function createLocalKtxLlmProviderFromConfig( return resolved ? (deps.createKtxLlmProvider ?? createKtxLlmProvider)(resolved) : null; } +function resolveSentenceTransformersBaseUrl( + value: string | undefined, + env: NodeJS.ProcessEnv, +): string | undefined { + if (!value) { + return undefined; + } + if (value === MANAGED_SENTENCE_TRANSFORMERS_BASE_URL) { + return resolveOptional(`env:${MANAGED_SENTENCE_TRANSFORMERS_BASE_URL_ENV}`, env); + } + return value; +} + export function resolveLocalKtxEmbeddingConfig( config: KtxProjectEmbeddingConfig, env: NodeJS.ProcessEnv, @@ -96,6 +112,22 @@ export function resolveLocalKtxEmbeddingConfig( if (config.backend === 'none') { return null; } + if (config.backend === 'sentence-transformers') { + const baseURL = resolveSentenceTransformersBaseUrl(config.sentenceTransformers?.base_url, env); + if (!baseURL) { + return null; + } + return { + backend: config.backend, + model: config.model ?? 'all-MiniLM-L6-v2', + dimensions: config.dimensions, + sentenceTransformers: { + baseURL, + pathPrefix: config.sentenceTransformers?.pathPrefix, + }, + batchSize: config.batchSize, + }; + } return { backend: config.backend, model: config.model ?? 'deterministic', diff --git a/packages/context/src/package-exports.test.ts b/packages/context/src/package-exports.test.ts index fd84c9c5..e22d64fa 100644 --- a/packages/context/src/package-exports.test.ts +++ b/packages/context/src/package-exports.test.ts @@ -132,6 +132,10 @@ describe('@ktx/context package exports', () => { expect(root.assertSearchBackendConformanceCase).toBeTypeOf('function'); expect(root.assertSearchBackendCapabilities).toBeTypeOf('function'); expect(root.createLocalKtxEmbeddingProviderFromConfig).toBeTypeOf('function'); + expect(root.MANAGED_SENTENCE_TRANSFORMERS_BASE_URL).toBe('managed:local-embeddings'); + expect(root.MANAGED_SENTENCE_TRANSFORMERS_BASE_URL_ENV).toBe( + 'KTX_MANAGED_SENTENCE_TRANSFORMERS_BASE_URL', + ); expect(agent).toBeDefined(); expect(agent.AgentRunnerService).toBeTypeOf('function'); expect(root.AgentRunnerService).toBeTypeOf('function');