fix: guide dev ingest llm setup (#15)

Co-authored-by: Andrey Avtomonov <7889985+andreybavt@users.noreply.github.com>
This commit is contained in:
Andrey Avtomonov 2026-05-12 10:26:07 +02:00 committed by GitHub
parent ff3e0edce3
commit a2dcd4eb08
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 86 additions and 4 deletions

View file

@ -32,6 +32,7 @@ import {
writeWarehouseConfig,
} from './ingest.test-utils.js';
import { resetVizFallbackWarningsForTest } from './viz-fallback.js';
import { runKtxSetup } from './setup.js';
describe('runKtxIngest', () => {
let tempDir: string;
@ -105,6 +106,75 @@ describe('runKtxIngest', () => {
expect(statusIo.stderr()).toBe('');
});
it('prints provider setup guidance when a skip-llm setup project runs dev ingest', async () => {
const projectDir = join(tempDir, 'project');
const setupIo = makeIo();
await expect(
runKtxSetup(
{
command: 'run',
projectDir,
mode: 'new',
agents: false,
agentScope: 'project',
agentInstallMode: 'cli',
skipAgents: true,
inputMode: 'disabled',
yes: true,
cliVersion: '0.0.0-test',
skipLlm: true,
skipEmbeddings: true,
databaseDrivers: ['postgres'],
databaseConnectionId: 'warehouse',
databaseUrl: 'env:WAREHOUSE_URL',
databaseSchemas: [],
enableHistoricSql: true,
skipDatabases: false,
skipSources: true,
},
setupIo.io,
{
databasesDeps: {
testConnection: async (_projectDir, _connectionId, io) => {
io.stdout.write('Driver: postgres\nTables: 1\n');
return 0;
},
scanConnection: async () => 0,
historicSqlProbe: async () => ({ ok: true, lines: ['PASS Historic SQL probe skipped in test'] }),
},
context: async () => ({ status: 'skipped', projectDir }),
},
),
).resolves.toBe(0);
const sourceDir = join(tempDir, 'source');
await mkdir(join(sourceDir, 'orders'), { recursive: true });
await writeFile(join(sourceDir, 'orders', 'orders.json'), '{"name":"orders"}\n', 'utf-8');
const runIo = makeIo();
await expect(
runKtxIngest(
{
command: 'run',
projectDir,
connectionId: 'warehouse',
adapter: 'historic-sql',
sourceDir,
outputMode: 'plain',
},
runIo.io,
),
).resolves.toBe(1);
expect(runIo.stdout()).toBe('');
expect(runIo.stderr()).toContain(
'ktx dev ingest run requires llm.provider.backend: anthropic, vertex, or gateway, or an injected agentRunner.',
);
expect(runIo.stderr()).toContain(
`ktx setup --project-dir ${projectDir} --anthropic-api-key-env ANTHROPIC_API_KEY --anthropic-model claude-sonnet-4-6 --no-input`,
);
});
it('routes metabase scheduled pulls to the fan-out runner and prints child summaries', async () => {
const projectDir = join(tempDir, 'project');
await writeMetabaseConfig(projectDir);

View file

@ -53,7 +53,13 @@ describe('createLocalBundleIngestRuntime', () => {
project,
adapters: [new FakeSourceAdapter()],
}),
).toThrow('ktx dev ingest run requires llm.provider.backend: anthropic, vertex, or gateway, or an injected agentRunner');
).toThrow(
[
'ktx dev ingest run requires llm.provider.backend: anthropic, vertex, or gateway, or an injected agentRunner.',
`Configure an Anthropic provider, then rerun ingest:`,
` ktx setup --project-dir ${project.projectDir} --anthropic-api-key-env ANTHROPIC_API_KEY --anthropic-model claude-sonnet-4-6 --no-input`,
].join('\n'),
);
});
it('builds runner deps with local SQLite stores and context tools enabled', async () => {

View file

@ -536,6 +536,14 @@ function nextLocalJobId(): string {
return `local-${Date.now().toString(36)}`;
}
function localIngestLlmProviderGuardMessage(projectDir: string): string {
return [
'ktx dev ingest run requires llm.provider.backend: anthropic, vertex, or gateway, or an injected agentRunner.',
'Configure an Anthropic provider, then rerun ingest:',
` ktx setup --project-dir ${projectDir} --anthropic-api-key-env ANTHROPIC_API_KEY --anthropic-model claude-sonnet-4-6 --no-input`,
].join('\n');
}
function resolveAgentRunner(options: CreateLocalBundleIngestRuntimeOptions): {
agentRunner: AgentRunnerService;
llmProvider?: KtxLlmProvider;
@ -548,9 +556,7 @@ function resolveAgentRunner(options: CreateLocalBundleIngestRuntimeOptions): {
}
if (!llmProvider) {
throw new Error(
'ktx dev ingest run requires llm.provider.backend: anthropic, vertex, or gateway, or an injected agentRunner',
);
throw new Error(localIngestLlmProviderGuardMessage(options.project.projectDir));
}
return {