mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-07 07:55:13 +02:00
fix(cli): report metabase ingest readiness
This commit is contained in:
parent
61ed276b44
commit
e05a6d43ab
2 changed files with 96 additions and 3 deletions
|
|
@ -3,6 +3,7 @@ import { tmpdir } from 'node:os';
|
|||
import { join } from 'node:path';
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { localFakeBundleReport, persistLocalBundleReport } from './ingest.test-utils.js';
|
||||
import { contextBuildCommands, writeKtxSetupContextState } from './setup-context.js';
|
||||
import { readKtxSetupStatus, runKtxSetup } from './setup.js';
|
||||
|
||||
|
|
@ -274,6 +275,62 @@ describe('setup status', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('reports Vertex LLM and context ready after a successful Metabase ingest report', async () => {
|
||||
await writeFile(
|
||||
join(tempDir, 'ktx.yaml'),
|
||||
[
|
||||
'project: revenue',
|
||||
'setup:',
|
||||
' database_connection_ids:',
|
||||
' - warehouse',
|
||||
' completed_steps:',
|
||||
' - project',
|
||||
' - databases',
|
||||
' - sources',
|
||||
'connections:',
|
||||
' warehouse:',
|
||||
' driver: postgres',
|
||||
' url: env:DATABASE_URL',
|
||||
' metabase:',
|
||||
' driver: metabase',
|
||||
' url: env:METABASE_URL',
|
||||
' api_key_ref: env:METABASE_API_KEY',
|
||||
' warehouse_connection_id: warehouse',
|
||||
'llm:',
|
||||
' provider:',
|
||||
' backend: vertex',
|
||||
' vertex:',
|
||||
' project: kaelio-dev',
|
||||
' location: us-east5',
|
||||
' models:',
|
||||
' default: claude-sonnet-4-6',
|
||||
'ingest:',
|
||||
' embeddings:',
|
||||
' backend: deterministic',
|
||||
' model: deterministic',
|
||||
' dimensions: 8',
|
||||
'',
|
||||
].join('\n'),
|
||||
'utf-8',
|
||||
);
|
||||
await persistLocalBundleReport(
|
||||
tempDir,
|
||||
localFakeBundleReport('metabase-job-1', {
|
||||
connectionId: 'warehouse',
|
||||
sourceKey: 'metabase',
|
||||
}),
|
||||
);
|
||||
|
||||
const status = await readKtxSetupStatus(tempDir);
|
||||
const io = makeIo();
|
||||
await expect(runKtxSetup({ command: 'status', projectDir: tempDir, json: false }, io.io)).resolves.toBe(0);
|
||||
|
||||
expect(status.llm).toMatchObject({ backend: 'vertex', ready: true, model: 'claude-sonnet-4-6' });
|
||||
expect(status.context).toMatchObject({ ready: true, status: 'completed' });
|
||||
expect(io.stdout()).toContain('LLM ready: yes (claude-sonnet-4-6)');
|
||||
expect(io.stdout()).toContain('KTX context built: yes');
|
||||
});
|
||||
|
||||
it('prints plain and JSON setup status', async () => {
|
||||
const plainIo = makeIo();
|
||||
const jsonIo = makeIo();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import { existsSync } from 'node:fs';
|
||||
import { join, resolve } from 'node:path';
|
||||
import { cancel, isCancel, select } from '@clack/prompts';
|
||||
import { loadKtxProject } from '@ktx/context/project';
|
||||
import { getLatestLocalIngestStatus, savedMemoryCountsForReport } from '@ktx/context/ingest';
|
||||
import { ktxLocalStateDbPath, loadKtxProject, type KtxLocalProject } from '@ktx/context/project';
|
||||
import type { KtxCliIo } from './cli-runtime.js';
|
||||
import type { KtxDemoArgs } from './demo.js';
|
||||
import { defaultDemoProjectDir } from './demo-assets.js';
|
||||
|
|
@ -152,6 +153,7 @@ export interface KtxSetupDeps {
|
|||
}
|
||||
|
||||
const SOURCE_DRIVERS = new Set(['dbt', 'metricflow', 'metabase', 'looker', 'lookml', 'notion']);
|
||||
const READY_LLM_BACKENDS = new Set(['anthropic', 'vertex', 'gateway']);
|
||||
|
||||
type KtxSetupEntryAction = 'setup' | 'new-project' | 'agents' | 'status' | 'demo' | 'exit';
|
||||
type KtxSetupFlowStep = 'models' | 'embeddings' | 'databases' | 'sources' | 'context' | 'agents';
|
||||
|
|
@ -234,7 +236,12 @@ async function runKtxSetupDemoFromEntryMenu(
|
|||
}
|
||||
|
||||
function llmReady(status: KtxSetupStatus['llm']): boolean {
|
||||
return status.backend === 'anthropic' && typeof status.model === 'string' && status.model.length > 0;
|
||||
return (
|
||||
status.backend !== undefined &&
|
||||
READY_LLM_BACKENDS.has(status.backend) &&
|
||||
typeof status.model === 'string' &&
|
||||
status.model.length > 0
|
||||
);
|
||||
}
|
||||
|
||||
function embeddingsReady(status: KtxSetupStatus['embeddings']): boolean {
|
||||
|
|
@ -259,6 +266,31 @@ function sourceConnections(config: Awaited<ReturnType<typeof loadKtxProject>>['c
|
|||
.sort((left, right) => left.connectionId.localeCompare(right.connectionId));
|
||||
}
|
||||
|
||||
type LocalIngestStatusReport = NonNullable<Awaited<ReturnType<typeof getLatestLocalIngestStatus>>>;
|
||||
|
||||
function reportHasSavedContext(report: LocalIngestStatusReport): boolean {
|
||||
if (report.body.failedWorkUnits.length > 0) {
|
||||
return false;
|
||||
}
|
||||
const counts = savedMemoryCountsForReport(report);
|
||||
return counts.wikiCount > 0 || counts.slCount > 0;
|
||||
}
|
||||
|
||||
async function readIngestContextStatus(project: KtxLocalProject): Promise<KtxSetupContextStatusSummary | null> {
|
||||
if (!existsSync(ktxLocalStateDbPath(project))) {
|
||||
return null;
|
||||
}
|
||||
const report = await getLatestLocalIngestStatus(project);
|
||||
if (!report || !reportHasSavedContext(report)) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
ready: true,
|
||||
status: 'completed',
|
||||
runId: report.runId,
|
||||
};
|
||||
}
|
||||
|
||||
export async function readKtxSetupStatus(projectDir: string): Promise<KtxSetupStatus> {
|
||||
const resolvedProjectDir = resolve(projectDir);
|
||||
if (!existsSync(join(resolvedProjectDir, 'ktx.yaml'))) {
|
||||
|
|
@ -291,6 +323,10 @@ export async function readKtxSetupStatus(projectDir: string): Promise<KtxSetupSt
|
|||
|
||||
const completedSteps = project.config.setup?.completed_steps ?? [];
|
||||
const contextState = await readKtxSetupContextState(resolvedProjectDir);
|
||||
const setupContextStatus = setupContextStatusFromState(contextState, {
|
||||
completedStep: completedSteps.includes('context'),
|
||||
});
|
||||
const ingestContextStatus = setupContextStatus.ready ? null : await readIngestContextStatus(project);
|
||||
const databaseIds = project.config.setup?.database_connection_ids ?? Object.keys(project.config.connections);
|
||||
const databasesComplete = completedSteps.includes('databases');
|
||||
const manifest = await readKtxAgentInstallManifest(resolvedProjectDir);
|
||||
|
|
@ -313,7 +349,7 @@ export async function readKtxSetupStatus(projectDir: string): Promise<KtxSetupSt
|
|||
...source,
|
||||
ready: completedSteps.includes('sources'),
|
||||
})),
|
||||
context: setupContextStatusFromState(contextState, { completedStep: completedSteps.includes('context') }),
|
||||
context: ingestContextStatus ?? setupContextStatus,
|
||||
agents,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue