diff --git a/packages/cli/src/admin-reindex.ts b/packages/cli/src/admin-reindex.ts index 8518fc2c..4b512e3a 100644 --- a/packages/cli/src/admin-reindex.ts +++ b/packages/cli/src/admin-reindex.ts @@ -1,18 +1,17 @@ import { createLocalKtxEmbeddingProviderFromConfig, KtxIngestEmbeddingPortAdapter, - MANAGED_SENTENCE_TRANSFORMERS_BASE_URL, type KtxEmbeddingPort, } from '@ktx/context'; import { reindexLocalIndexes, type ReindexScopeResult, type ReindexSummary } from '@ktx/context/index-sync'; -import { loadKtxProject, type KtxLocalProject } from '@ktx/context/project'; +import { type KtxLocalProject } from '@ktx/context/project'; import { Option, type Command } from '@commander-js/extra-typings'; import { cancel, intro, log, note, outro } from '@clack/prompts'; import type { KtxCliCommandContext } from './cli-program.js'; +import { loadKtxCliProject } from './cli-project.js'; import type { KtxCliIo } from './cli-runtime.js'; import { resolveOutputMode } from './io/mode.js'; import { green, red, SYMBOLS } from './io/symbols.js'; -import { ensureManagedLocalEmbeddingsDaemon } from './managed-local-embeddings.js'; export interface KtxAdminReindexArgs { projectDir: string; @@ -49,30 +48,11 @@ export function registerAdminReindexCommand(admin: Command, context: KtxCliComma }); } -async function resolveReindexEmbeddingService( - project: KtxLocalProject, - args: KtxAdminReindexArgs, - io: KtxCliIo, -): Promise { +function resolveReindexEmbeddingService(project: KtxLocalProject): KtxEmbeddingPort | null { const config = project.config.ingest.embeddings; if (config.backend === 'none') { return null; } - - if ( - config.backend === 'sentence-transformers' && - config.sentenceTransformers?.base_url === MANAGED_SENTENCE_TRANSFORMERS_BASE_URL - ) { - const daemon = await ensureManagedLocalEmbeddingsDaemon({ - cliVersion: args.cliVersion, - projectDir: project.projectDir, - installPolicy: 'never', - io, - }); - const provider = createLocalKtxEmbeddingProviderFromConfig(config, { env: { ...process.env, ...daemon.env } }); - return provider ? new KtxIngestEmbeddingPortAdapter(provider) : null; - } - const provider = createLocalKtxEmbeddingProviderFromConfig(config); return provider ? new KtxIngestEmbeddingPortAdapter(provider) : null; } @@ -186,8 +166,13 @@ function renderReindexPretty(summary: ReindexSummary, io: KtxCliIo): void { async function runKtxAdminReindex(args: KtxAdminReindexArgs, io: KtxCliIo = process): Promise { try { - const project = await loadKtxProject({ projectDir: args.projectDir }); - const embeddingService = await resolveReindexEmbeddingService(project, args, io); + const project = await loadKtxCliProject({ + projectDir: args.projectDir, + cliVersion: args.cliVersion, + installPolicy: 'never', + io, + }); + const embeddingService = resolveReindexEmbeddingService(project); const summary = await reindexLocalIndexes(project, { force: args.force, embeddingService }); const mode = resolveOutputMode({ explicit: args.output, json: args.json, io }); diff --git a/packages/cli/src/cli-project.test.ts b/packages/cli/src/cli-project.test.ts new file mode 100644 index 00000000..0565a3c3 --- /dev/null +++ b/packages/cli/src/cli-project.test.ts @@ -0,0 +1,182 @@ +import { describe, expect, it, vi } from 'vitest'; +import { MANAGED_SENTENCE_TRANSFORMERS_BASE_URL } from '@ktx/context'; +import { buildDefaultKtxProjectConfig, type KtxLocalProject, type KtxProjectConfig } from '@ktx/context/project'; +import { + loadKtxCliProject, + projectNeedsManagedLocalEmbeddings, + substituteManagedLocalEmbeddingsUrl, +} from './cli-project.js'; +import type { ManagedLocalEmbeddingsDaemon } from './managed-local-embeddings.js'; + +const RESOLVED_BASE_URL = 'http://127.0.0.1:51234'; + +function makeIo() { + let stderr = ''; + return { + io: { + stdout: { write: (_chunk: string) => {} }, + stderr: { + write: (chunk: string) => { + stderr += chunk; + }, + }, + }, + stderr: () => stderr, + }; +} + +function projectWithConfig(config: KtxProjectConfig): KtxLocalProject { + return { + projectDir: '/work/proj', + configPath: '/work/proj/ktx.yaml', + config, + coreConfig: {} as KtxLocalProject['coreConfig'], + git: {} as KtxLocalProject['git'], + fileStore: {} as KtxLocalProject['fileStore'], + }; +} + +function withManagedIngestEmbedding(config: KtxProjectConfig): KtxProjectConfig { + return { + ...config, + ingest: { + ...config.ingest, + embeddings: { + backend: 'sentence-transformers', + model: 'all-MiniLM-L6-v2', + dimensions: 384, + sentenceTransformers: { base_url: MANAGED_SENTENCE_TRANSFORMERS_BASE_URL, pathPrefix: '' }, + }, + }, + }; +} + +function withManagedScanEnrichmentEmbedding(config: KtxProjectConfig): KtxProjectConfig { + return { + ...config, + scan: { + ...config.scan, + enrichment: { + ...config.scan.enrichment, + embeddings: { + backend: 'sentence-transformers', + model: 'all-MiniLM-L6-v2', + dimensions: 384, + sentenceTransformers: { base_url: MANAGED_SENTENCE_TRANSFORMERS_BASE_URL, pathPrefix: '' }, + }, + }, + }, + }; +} + +const fakeDaemon: ManagedLocalEmbeddingsDaemon = { + baseUrl: RESOLVED_BASE_URL, + stdoutLog: '/work/proj/.ktx/runtime/daemon.stdout.log', + stderrLog: '/work/proj/.ktx/runtime/daemon.stderr.log', +}; + +describe('projectNeedsManagedLocalEmbeddings', () => { + it('returns false when neither ingest nor scan embeddings reference the managed sentinel', () => { + expect(projectNeedsManagedLocalEmbeddings(buildDefaultKtxProjectConfig())).toBe(false); + }); + + it('returns true when ingest.embeddings uses the managed sentinel', () => { + expect(projectNeedsManagedLocalEmbeddings(withManagedIngestEmbedding(buildDefaultKtxProjectConfig()))).toBe(true); + }); + + it('returns true when scan.enrichment.embeddings uses the managed sentinel', () => { + expect( + projectNeedsManagedLocalEmbeddings(withManagedScanEnrichmentEmbedding(buildDefaultKtxProjectConfig())), + ).toBe(true); + }); +}); + +describe('substituteManagedLocalEmbeddingsUrl', () => { + it('rewrites the managed sentinel in both ingest.embeddings and scan.enrichment.embeddings', () => { + const config = withManagedScanEnrichmentEmbedding(withManagedIngestEmbedding(buildDefaultKtxProjectConfig())); + const resolved = substituteManagedLocalEmbeddingsUrl(config, RESOLVED_BASE_URL); + expect(resolved.ingest.embeddings.sentenceTransformers?.base_url).toBe(RESOLVED_BASE_URL); + expect(resolved.scan.enrichment.embeddings?.sentenceTransformers?.base_url).toBe(RESOLVED_BASE_URL); + }); + + it('returns the input unchanged when no sentinel is present', () => { + const config = buildDefaultKtxProjectConfig(); + const resolved = substituteManagedLocalEmbeddingsUrl(config, RESOLVED_BASE_URL); + expect(resolved.ingest.embeddings).toEqual(config.ingest.embeddings); + expect(resolved.scan.enrichment.embeddings).toEqual(config.scan.enrichment.embeddings); + }); + + it('does not touch non-sentinel sentence-transformers URLs', () => { + const config: KtxProjectConfig = { + ...buildDefaultKtxProjectConfig(), + ingest: { + ...buildDefaultKtxProjectConfig().ingest, + embeddings: { + backend: 'sentence-transformers', + model: 'all-MiniLM-L6-v2', + dimensions: 384, + sentenceTransformers: { base_url: 'http://localhost:9999', pathPrefix: '' }, + }, + }, + }; + const resolved = substituteManagedLocalEmbeddingsUrl(config, RESOLVED_BASE_URL); + expect(resolved.ingest.embeddings.sentenceTransformers?.base_url).toBe('http://localhost:9999'); + }); +}); + +describe('loadKtxCliProject', () => { + it('returns the project unchanged and does not start the daemon when no sentinel is present', async () => { + const io = makeIo(); + const project = projectWithConfig(buildDefaultKtxProjectConfig()); + const loadProject = vi.fn(async () => project); + const ensureLocalEmbeddings = vi.fn(async () => fakeDaemon); + + const result = await loadKtxCliProject( + { projectDir: '/work/proj', cliVersion: '0.2.0', installPolicy: 'never', io: io.io }, + { loadProject, ensureLocalEmbeddings }, + ); + + expect(result).toBe(project); + expect(ensureLocalEmbeddings).not.toHaveBeenCalled(); + }); + + it('starts the daemon and substitutes the resolved URL when ingest.embeddings uses the sentinel', async () => { + const io = makeIo(); + const project = projectWithConfig(withManagedIngestEmbedding(buildDefaultKtxProjectConfig())); + const loadProject = vi.fn(async () => project); + const ensureLocalEmbeddings = vi.fn(async () => fakeDaemon); + + const result = await loadKtxCliProject( + { projectDir: '/work/proj', cliVersion: '0.2.0', installPolicy: 'never', io: io.io }, + { loadProject, ensureLocalEmbeddings }, + ); + + expect(ensureLocalEmbeddings).toHaveBeenCalledWith({ + cliVersion: '0.2.0', + projectDir: '/work/proj', + installPolicy: 'never', + io: io.io, + }); + expect(result.config.ingest.embeddings.sentenceTransformers?.base_url).toBe(RESOLVED_BASE_URL); + }); + + it('does not mutate process.env', async () => { + const io = makeIo(); + const before = process.env.KTX_MANAGED_SENTENCE_TRANSFORMERS_BASE_URL; + delete process.env.KTX_MANAGED_SENTENCE_TRANSFORMERS_BASE_URL; + try { + const project = projectWithConfig(withManagedIngestEmbedding(buildDefaultKtxProjectConfig())); + await loadKtxCliProject( + { projectDir: '/work/proj', cliVersion: '0.2.0', installPolicy: 'never', io: io.io }, + { loadProject: vi.fn(async () => project), ensureLocalEmbeddings: vi.fn(async () => fakeDaemon) }, + ); + expect(process.env.KTX_MANAGED_SENTENCE_TRANSFORMERS_BASE_URL).toBeUndefined(); + } finally { + if (before === undefined) { + delete process.env.KTX_MANAGED_SENTENCE_TRANSFORMERS_BASE_URL; + } else { + process.env.KTX_MANAGED_SENTENCE_TRANSFORMERS_BASE_URL = before; + } + } + }); +}); diff --git a/packages/cli/src/cli-project.ts b/packages/cli/src/cli-project.ts new file mode 100644 index 00000000..8e8df669 --- /dev/null +++ b/packages/cli/src/cli-project.ts @@ -0,0 +1,91 @@ +import { MANAGED_SENTENCE_TRANSFORMERS_BASE_URL } from '@ktx/context'; +import { loadKtxProject, type KtxLocalProject } from '@ktx/context/project'; +import type { KtxProjectConfig, KtxProjectEmbeddingConfig } from '@ktx/context/project'; +import type { KtxCliIo } from './cli-runtime.js'; +import { + ensureManagedLocalEmbeddingsDaemon, + type ManagedLocalEmbeddingsDaemon, +} from './managed-local-embeddings.js'; +import type { KtxManagedPythonInstallPolicy } from './managed-python-command.js'; + +export interface LoadKtxCliProjectOptions { + projectDir: string; + cliVersion: string; + installPolicy: KtxManagedPythonInstallPolicy; + io: KtxCliIo; +} + +export interface LoadKtxCliProjectDeps { + loadProject?: typeof loadKtxProject; + ensureLocalEmbeddings?: ( + options: Parameters[0], + ) => Promise; +} + +export async function loadKtxCliProject( + options: LoadKtxCliProjectOptions, + deps: LoadKtxCliProjectDeps = {}, +): Promise { + const loadProject = deps.loadProject ?? loadKtxProject; + const ensureLocalEmbeddings = deps.ensureLocalEmbeddings ?? ensureManagedLocalEmbeddingsDaemon; + + const project = await loadProject({ projectDir: options.projectDir }); + if (!projectNeedsManagedLocalEmbeddings(project.config)) { + return project; + } + + const daemon = await ensureLocalEmbeddings({ + cliVersion: options.cliVersion, + projectDir: options.projectDir, + installPolicy: options.installPolicy, + io: options.io, + }); + + return { + ...project, + config: substituteManagedLocalEmbeddingsUrl(project.config, daemon.baseUrl), + }; +} + +export function projectNeedsManagedLocalEmbeddings(config: KtxProjectConfig): boolean { + return ( + embeddingUsesManagedSentinel(config.ingest.embeddings) || + embeddingUsesManagedSentinel(config.scan.enrichment.embeddings) + ); +} + +export function substituteManagedLocalEmbeddingsUrl( + config: KtxProjectConfig, + baseUrl: string, +): KtxProjectConfig { + const ingestEmbeddings = rewriteManagedEmbeddingConfig(config.ingest.embeddings, baseUrl); + const scanEnrichmentEmbeddings = rewriteManagedEmbeddingConfig(config.scan.enrichment.embeddings, baseUrl); + return { + ...config, + ingest: { ...config.ingest, embeddings: ingestEmbeddings }, + scan: { + ...config.scan, + enrichment: { ...config.scan.enrichment, embeddings: scanEnrichmentEmbeddings }, + }, + }; +} + +function embeddingUsesManagedSentinel(embedding: KtxProjectEmbeddingConfig | undefined): boolean { + return embedding?.sentenceTransformers?.base_url === MANAGED_SENTENCE_TRANSFORMERS_BASE_URL; +} + +function rewriteManagedEmbeddingConfig( + embedding: T, + baseUrl: string, +): T { + if (!embedding || !embeddingUsesManagedSentinel(embedding)) { + return embedding; + } + return { + ...embedding, + sentenceTransformers: { + ...embedding.sentenceTransformers, + base_url: baseUrl, + }, + } as T; +} diff --git a/packages/cli/src/ingest.ts b/packages/cli/src/ingest.ts index a45308f1..0d85634b 100644 --- a/packages/cli/src/ingest.ts +++ b/packages/cli/src/ingest.ts @@ -18,7 +18,8 @@ import { sanitizeMemoryFlowError, } from '@ktx/context/ingest'; import type { KtxSqlQueryExecutorPort } from '@ktx/context/connections'; -import { loadKtxProject, type KtxLocalProject } from '@ktx/context/project'; +import { type KtxLocalProject } from '@ktx/context/project'; +import { loadKtxCliProject } from './cli-project.js'; import { createKtxCliIngestQueryExecutor } from './ingest-query-executor.js'; import { readIngestReportSnapshotFile } from './ingest-report-file.js'; import { createCliOperationalLogger } from './io/logger.js'; @@ -529,7 +530,7 @@ function assertReportMatchesReplayId(report: IngestReportSnapshot, requestedId: } async function readStoredIngestReport( - project: Awaited>, + project: KtxLocalProject, runId: string | undefined, ): Promise { return runId ? await getLocalIngestStatus(project, runId) : await getLatestLocalIngestStatus(project); @@ -681,7 +682,14 @@ export async function runKtxIngest( deps: KtxIngestDeps = {}, ): Promise { try { - const project = await loadKtxProject({ projectDir: args.projectDir }); + const cliVersion = args.command === 'run' ? args.cliVersion : undefined; + const runtimeInstallPolicy = args.command === 'run' ? args.runtimeInstallPolicy : undefined; + const project = await loadKtxCliProject({ + projectDir: args.projectDir, + cliVersion: cliVersion ?? '0.0.0-private', + installPolicy: runtimeInstallPolicy ?? 'never', + io, + }); const env = deps.env ?? process.env; if (args.command === 'run') { const ingestProject = diff --git a/packages/cli/src/managed-local-embeddings.test.ts b/packages/cli/src/managed-local-embeddings.test.ts index 85fa00c9..468e53d3 100644 --- a/packages/cli/src/managed-local-embeddings.test.ts +++ b/packages/cli/src/managed-local-embeddings.test.ts @@ -1,8 +1,5 @@ import { describe, expect, it, vi } from 'vitest'; -import { - MANAGED_SENTENCE_TRANSFORMERS_BASE_URL, - MANAGED_SENTENCE_TRANSFORMERS_BASE_URL_ENV, -} from '@ktx/context'; +import { MANAGED_SENTENCE_TRANSFORMERS_BASE_URL } from '@ktx/context'; import { ensureManagedLocalEmbeddingsDaemon, managedLocalEmbeddingHealthConfig, @@ -152,9 +149,6 @@ describe('ensureManagedLocalEmbeddingsDaemon', () => { baseUrl: 'http://127.0.0.1:61234', stdoutLog: '/work/proj/.ktx/runtime/daemon.stdout.log', stderrLog: '/work/proj/.ktx/runtime/daemon.stderr.log', - env: { - [MANAGED_SENTENCE_TRANSFORMERS_BASE_URL_ENV]: 'http://127.0.0.1:61234', - }, }); expect(ensureRuntime).toHaveBeenCalledWith({ diff --git a/packages/cli/src/managed-local-embeddings.ts b/packages/cli/src/managed-local-embeddings.ts index f485a942..b8c01b16 100644 --- a/packages/cli/src/managed-local-embeddings.ts +++ b/packages/cli/src/managed-local-embeddings.ts @@ -1,7 +1,4 @@ -import { - MANAGED_SENTENCE_TRANSFORMERS_BASE_URL, - MANAGED_SENTENCE_TRANSFORMERS_BASE_URL_ENV, -} from '@ktx/context'; +import { MANAGED_SENTENCE_TRANSFORMERS_BASE_URL } from '@ktx/context'; import type { KtxProjectEmbeddingConfig } from '@ktx/context/project'; import type { KtxEmbeddingConfig } from '@ktx/llm'; import type { KtxCliIo } from './cli-runtime.js'; @@ -16,7 +13,6 @@ export interface ManagedLocalEmbeddingsDaemon { baseUrl: string; stdoutLog: string; stderrLog: string; - env: Record; } export interface ManagedLocalEmbeddingsOptions { @@ -95,8 +91,5 @@ export async function ensureManagedLocalEmbeddingsDaemon( baseUrl: daemon.baseUrl, stdoutLog: daemon.state.stdoutLog, stderrLog: daemon.state.stderrLog, - env: { - [MANAGED_SENTENCE_TRANSFORMERS_BASE_URL_ENV]: daemon.baseUrl, - }, }; } diff --git a/packages/cli/src/public-ingest.ts b/packages/cli/src/public-ingest.ts index 2c0a2856..3dcc87ad 100644 --- a/packages/cli/src/public-ingest.ts +++ b/packages/cli/src/public-ingest.ts @@ -1,4 +1,5 @@ -import { type KtxLocalProject, type KtxProjectConnectionConfig, loadKtxProject } from '@ktx/context/project'; +import { type KtxLocalProject, type KtxProjectConnectionConfig } from '@ktx/context/project'; +import { loadKtxCliProject } from './cli-project.js'; import type { KtxProgressPort } from '@ktx/context/scan'; import type { KtxCliIo } from './index.js'; import type { KtxIngestArgs, KtxIngestDeps, KtxIngestProgressUpdate } from './ingest.js'; @@ -90,7 +91,7 @@ export type KtxPublicIngestProject = Pick[0]) => Promise; + loadProject?: (options: { projectDir: string }) => Promise; runScan?: (args: KtxScanArgs, io: KtxCliIo, deps?: KtxScanDeps) => Promise; runIngest?: (args: KtxIngestArgs, io: KtxCliIo, deps?: KtxIngestDeps) => Promise; runContextBuild?: ( @@ -867,7 +868,15 @@ export async function runKtxPublicIngest( io: KtxCliIo, deps: KtxPublicIngestDeps = {}, ): Promise { - const loadProject = deps.loadProject ?? loadKtxProject; + const loadProject = + deps.loadProject ?? + ((options: { projectDir: string }) => + loadKtxCliProject({ + projectDir: options.projectDir, + cliVersion: args.cliVersion ?? '0.0.0-private', + installPolicy: args.runtimeInstallPolicy ?? 'never', + io, + })); const project = await loadProject({ projectDir: args.projectDir }); if (shouldUseForegroundContextBuildView(args, io)) { const plan = buildPublicIngestPlan(project, args); diff --git a/packages/cli/src/scan.ts b/packages/cli/src/scan.ts index d7334fac..68d0db35 100644 --- a/packages/cli/src/scan.ts +++ b/packages/cli/src/scan.ts @@ -1,4 +1,3 @@ -import { loadKtxProject } from '@ktx/context/project'; import { type KtxProgressPort, type KtxScanMode, @@ -6,6 +5,7 @@ import { type KtxScanWarning, runLocalScan, } from '@ktx/context/scan'; +import { loadKtxCliProject } from './cli-project.js'; import type { KtxCliIo } from './index.js'; import { createKtxCliLocalIngestAdapters } from './local-adapters.js'; import { createKtxCliScanConnector } from './local-scan-connectors.js'; @@ -313,7 +313,12 @@ export function createCliScanProgress( export async function runKtxScan(args: KtxScanArgs, io: KtxCliIo = process, deps: KtxScanDeps = {}): Promise { try { - const project = await loadKtxProject({ projectDir: args.projectDir }); + const project = await loadKtxCliProject({ + projectDir: args.projectDir, + cliVersion: args.cliVersion ?? '0.0.0-private', + installPolicy: args.runtimeInstallPolicy ?? 'never', + io, + }); const managedDaemon = managedDaemonOptionsForScanRun(args, deps.runtimeIo ?? io); const connector = args.mode !== 'structural' || args.detectRelationships diff --git a/packages/context/src/llm/index.ts b/packages/context/src/llm/index.ts index 64d5a26e..6acec733 100644 --- a/packages/context/src/llm/index.ts +++ b/packages/context/src/llm/index.ts @@ -38,7 +38,6 @@ export { } from './debug-request-recorder.js'; export { MANAGED_SENTENCE_TRANSFORMERS_BASE_URL, - MANAGED_SENTENCE_TRANSFORMERS_BASE_URL_ENV, createLocalKtxEmbeddingProviderFromConfig, createLocalKtxLlmProviderFromConfig, createLocalKtxLlmRuntimeFromConfig, diff --git a/packages/context/src/llm/local-config.test.ts b/packages/context/src/llm/local-config.test.ts index 23487e36..2d3475bc 100644 --- a/packages/context/src/llm/local-config.test.ts +++ b/packages/context/src/llm/local-config.test.ts @@ -6,7 +6,6 @@ import { } from '../project/config.js'; import { MANAGED_SENTENCE_TRANSFORMERS_BASE_URL, - MANAGED_SENTENCE_TRANSFORMERS_BASE_URL_ENV, createLocalKtxEmbeddingProviderFromConfig, createLocalKtxLlmProviderFromConfig, resolveLocalKtxEmbeddingConfig, @@ -152,32 +151,7 @@ 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', () => { + it('returns null when sentence-transformers base_url is still the unresolved managed sentinel', () => { const config: KtxProjectEmbeddingConfig = { backend: 'sentence-transformers', model: 'all-MiniLM-L6-v2', diff --git a/packages/context/src/llm/local-config.ts b/packages/context/src/llm/local-config.ts index e63a5ed1..b4a41753 100644 --- a/packages/context/src/llm/local-config.ts +++ b/packages/context/src/llm/local-config.ts @@ -23,7 +23,6 @@ interface LocalConfigDeps { } 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; @@ -141,19 +140,6 @@ export function createLocalKtxLlmRuntimeFromConfig( return (deps.createAiSdkRuntime ?? ((runtimeDeps) => new AiSdkKtxLlmRuntime(runtimeDeps)))({ llmProvider }); } -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, @@ -162,8 +148,8 @@ export function resolveLocalKtxEmbeddingConfig( return null; } if (config.backend === 'sentence-transformers') { - const baseURL = resolveSentenceTransformersBaseUrl(config.sentenceTransformers?.base_url, env); - if (!baseURL) { + const baseURL = config.sentenceTransformers?.base_url; + if (!baseURL || baseURL === MANAGED_SENTENCE_TRANSFORMERS_BASE_URL) { return null; } return { diff --git a/packages/context/src/package-exports.test.ts b/packages/context/src/package-exports.test.ts index ea6c6592..3dae6c7d 100644 --- a/packages/context/src/package-exports.test.ts +++ b/packages/context/src/package-exports.test.ts @@ -132,9 +132,6 @@ describe('@ktx/context package exports', () => { 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');