feat(cli): pass managed daemon options to serve ingest

This commit is contained in:
Andrey Avtomonov 2026-05-11 12:40:31 +02:00
parent 0fc5809e02
commit 2982983a83
2 changed files with 81 additions and 4 deletions

View file

@ -162,6 +162,9 @@ describe('runKtxServeStdio', () => {
expect.objectContaining({
localIngest: expect.objectContaining({
adapters: expect.any(Array),
pullConfigOptions: {
databaseIntrospectionUrl: 'http://127.0.0.1:8765',
},
}),
localScan: expect.objectContaining({
adapters: createdAdapters,
@ -174,6 +177,61 @@ describe('runKtxServeStdio', () => {
});
});
it('passes managed daemon options to MCP local ingest adapters and pull-config options', async () => {
const project = { projectDir: '/tmp/ktx-project', config: { connections: {} } } as never;
const adapters = [{ source: 'looker', skillNames: [] }];
const createIngestAdapters = vi.fn(() => adapters);
const createContextTools = vi.fn(() => ({ connections: { list: async () => [] } }));
const managedRuntimeIo = makeManagedRuntimeIo();
await expect(
runKtxServeStdio(
{
mcp: 'stdio',
projectDir: '/tmp/ktx-project',
userId: 'agent',
semanticCompute: false,
semanticComputeUrl: undefined,
databaseIntrospectionUrl: undefined,
executeQueries: false,
memoryCapture: false,
memoryModel: undefined,
cliVersion: '0.2.0',
runtimeInstallPolicy: 'auto',
},
{
loadProject: async () => project,
createContextTools,
createIngestAdapters,
managedRuntimeIo: managedRuntimeIo.io,
createServer: vi.fn(() => ({ connect: vi.fn(async () => undefined) }) as never),
createTransport: vi.fn(() => ({}) as never),
stderr: { write: vi.fn() },
},
),
).resolves.toBe(0);
const expectedManagedDaemon = {
cliVersion: '0.2.0',
installPolicy: 'auto',
io: managedRuntimeIo.io,
};
expect(createIngestAdapters).toHaveBeenCalledWith(project, {
managedDaemon: expectedManagedDaemon,
});
expect(createContextTools).toHaveBeenCalledWith(
project,
expect.objectContaining({
localIngest: expect.objectContaining({
adapters,
pullConfigOptions: {
managedDaemon: expectedManagedDaemon,
},
}),
}),
);
});
it('uses CLI-native local ingest adapters for standalone scan tools', async () => {
const project = { projectDir: '/tmp/ktx-project', config: { connections: {} } } as never;
const createContextTools = vi.fn(() => ({}) as never);

View file

@ -21,6 +21,7 @@ import {
createManagedPythonSemanticLayerComputePort,
type KtxManagedPythonInstallPolicy,
} from './managed-python-command.js';
import type { ManagedPythonCoreDaemonOptions } from './managed-python-http.js';
import { profileMark } from './startup-profile.js';
profileMark('module:serve');
@ -57,7 +58,7 @@ interface KtxServeDeps {
createManagedSemanticLayerCompute?: typeof createManagedPythonSemanticLayerComputePort;
managedRuntimeIo?: KtxCliIo;
createHttpSemanticLayerCompute?: (baseUrl: string) => KtxSemanticLayerComputePort;
createIngestAdapters?: typeof createDefaultLocalIngestAdapters;
createIngestAdapters?: typeof createKtxCliLocalIngestAdapters;
createQueryExecutor?: () => KtxSqlQueryExecutorPort;
createMemoryCapture?: typeof createLocalProjectMemoryCapture;
createServer?: typeof createDefaultKtxMcpServer;
@ -72,6 +73,20 @@ function requiredManagedRuntimeCliVersion(args: KtxServeArgs): string {
return args.cliVersion;
}
function managedDaemonOptionsForServe(
args: KtxServeArgs,
deps: KtxServeDeps,
): ManagedPythonCoreDaemonOptions | undefined {
if (args.databaseIntrospectionUrl || !args.cliVersion) {
return undefined;
}
return {
cliVersion: args.cliVersion,
installPolicy: args.runtimeInstallPolicy ?? 'prompt',
io: deps.managedRuntimeIo ?? process,
};
}
async function createServeSemanticLayerCompute(
args: KtxServeArgs,
deps: KtxServeDeps,
@ -109,9 +124,12 @@ export async function runKtxServeStdio(args: KtxServeArgs, deps: KtxServeDeps =
? (deps.createQueryExecutor ?? createDefaultLocalQueryExecutor)()
: undefined;
const createIngestAdapters = deps.createIngestAdapters ?? createKtxCliLocalIngestAdapters;
const localAdapters = createIngestAdapters(project, {
databaseIntrospectionUrl: args.databaseIntrospectionUrl,
});
const managedDaemon = managedDaemonOptionsForServe(args, deps);
const localAdapterOptions = {
...(args.databaseIntrospectionUrl ? { databaseIntrospectionUrl: args.databaseIntrospectionUrl } : {}),
...(managedDaemon ? { managedDaemon } : {}),
};
const localAdapters = createIngestAdapters(project, localAdapterOptions);
const llmProvider = args.memoryCapture
? (createLocalKtxLlmProviderFromConfig(project.config.llm) ?? undefined)
: undefined;
@ -123,6 +141,7 @@ export async function runKtxServeStdio(args: KtxServeArgs, deps: KtxServeDeps =
: undefined;
const localIngest: LocalIngestMcpOptions = {
adapters: localAdapters,
pullConfigOptions: localAdapterOptions,
...(semanticLayerCompute ? { semanticLayerCompute } : {}),
...(queryExecutor ? { queryExecutor } : {}),
};