@kaelio/ktx 0.13.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/python/{kaelio_ktx-0.13.0-py3-none-any.whl → kaelio_ktx-0.14.0-py3-none-any.whl} +0 -0
- package/assets/python/manifest.json +4 -4
- package/dist/.tsbuildinfo +1 -1
- package/dist/cli-program.js +1 -1
- package/dist/commands/ingest-commands.d.ts +9 -0
- package/dist/commands/ingest-commands.js +37 -1
- package/dist/commands/knowledge-commands.js +3 -0
- package/dist/commands/setup-commands.js +14 -1
- package/dist/connection-drivers.d.ts +2 -0
- package/dist/connection-drivers.js +7 -3
- package/dist/connection.d.ts +3 -0
- package/dist/connection.js +27 -0
- package/dist/connectors/bigquery/connector.d.ts +17 -6
- package/dist/connectors/bigquery/connector.js +152 -76
- package/dist/connectors/bigquery/dialect.d.ts +2 -2
- package/dist/connectors/clickhouse/connector.d.ts +1 -0
- package/dist/connectors/clickhouse/connector.js +45 -16
- package/dist/connectors/clickhouse/dialect.d.ts +2 -2
- package/dist/connectors/mongodb/connector.d.ts +69 -0
- package/dist/connectors/mongodb/connector.js +307 -0
- package/dist/connectors/mongodb/dialect.d.ts +17 -0
- package/dist/connectors/mongodb/dialect.js +50 -0
- package/dist/connectors/mongodb/live-database-introspection.d.ts +10 -0
- package/dist/connectors/mongodb/live-database-introspection.js +24 -0
- package/dist/connectors/mongodb/schema-inference.d.ts +20 -0
- package/dist/connectors/mongodb/schema-inference.js +110 -0
- package/dist/connectors/mysql/connector.d.ts +1 -0
- package/dist/connectors/mysql/connector.js +18 -2
- package/dist/connectors/mysql/dialect.d.ts +2 -2
- package/dist/connectors/postgres/connector.d.ts +1 -0
- package/dist/connectors/postgres/connector.js +20 -3
- package/dist/connectors/postgres/dialect.d.ts +2 -2
- package/dist/connectors/snowflake/connector.d.ts +1 -0
- package/dist/connectors/snowflake/connector.js +27 -3
- package/dist/connectors/snowflake/dialect.d.ts +2 -2
- package/dist/connectors/sqlite/connector.d.ts +11 -1
- package/dist/connectors/sqlite/connector.js +120 -17
- package/dist/connectors/sqlite/dialect.d.ts +2 -2
- package/dist/connectors/sqlite/read-query-child.d.ts +1 -0
- package/dist/connectors/sqlite/read-query-child.js +23 -0
- package/dist/connectors/sqlserver/connector.d.ts +2 -0
- package/dist/connectors/sqlserver/connector.js +23 -5
- package/dist/connectors/sqlserver/dialect.d.ts +2 -2
- package/dist/context/cache/content-result-cache.d.ts +36 -0
- package/dist/context/cache/content-result-cache.js +14 -0
- package/dist/context/cache/sqlite-content-result-cache.d.ts +18 -0
- package/dist/context/cache/sqlite-content-result-cache.js +223 -0
- package/dist/context/connections/bigquery-identifiers.d.ts +1 -0
- package/dist/context/connections/bigquery-identifiers.js +7 -0
- package/dist/context/connections/configured-connections.d.ts +9 -0
- package/dist/context/connections/configured-connections.js +18 -0
- package/dist/context/connections/dialects.d.ts +30 -4
- package/dist/context/connections/dialects.js +38 -11
- package/dist/context/connections/drivers.js +21 -0
- package/dist/context/connections/gdrive-config.d.ts +19 -0
- package/dist/context/connections/gdrive-config.js +57 -0
- package/dist/context/connections/query-deadline.d.ts +31 -0
- package/dist/context/connections/query-deadline.js +37 -0
- package/dist/context/connections/read-only-sql.d.ts +5 -0
- package/dist/context/connections/read-only-sql.js +139 -1
- package/dist/context/ingest/adapters/gdrive/chunk.d.ts +3 -0
- package/dist/context/ingest/adapters/gdrive/chunk.js +74 -0
- package/dist/context/ingest/adapters/gdrive/detect.d.ts +1 -0
- package/dist/context/ingest/adapters/gdrive/detect.js +20 -0
- package/dist/context/ingest/adapters/gdrive/fetch.d.ts +6 -0
- package/dist/context/ingest/adapters/gdrive/fetch.js +95 -0
- package/dist/context/ingest/adapters/gdrive/gdrive-client.d.ts +30 -0
- package/dist/context/ingest/adapters/gdrive/gdrive-client.js +132 -0
- package/dist/context/ingest/adapters/gdrive/gdrive.adapter.d.ts +11 -0
- package/dist/context/ingest/adapters/gdrive/gdrive.adapter.js +27 -0
- package/dist/context/ingest/adapters/gdrive/normalize.d.ts +2 -0
- package/dist/context/ingest/adapters/gdrive/normalize.js +256 -0
- package/dist/context/ingest/adapters/gdrive/types.d.ts +153 -0
- package/dist/context/ingest/adapters/gdrive/types.js +36 -0
- package/dist/context/ingest/adapters/live-database/daemon-introspection.js +24 -0
- package/dist/context/ingest/adapters/live-database/fetch-report.d.ts +8 -0
- package/dist/context/ingest/adapters/live-database/fetch-report.js +37 -0
- package/dist/context/ingest/adapters/live-database/live-database.adapter.d.ts +2 -1
- package/dist/context/ingest/adapters/live-database/live-database.adapter.js +9 -2
- package/dist/context/ingest/adapters/live-database/manifest.d.ts +2 -0
- package/dist/context/ingest/adapters/live-database/manifest.js +8 -4
- package/dist/context/ingest/adapters/live-database/scan-outcome.d.ts +17 -0
- package/dist/context/ingest/adapters/live-database/scan-outcome.js +40 -0
- package/dist/context/ingest/adapters/live-database/stage.js +5 -5
- package/dist/context/ingest/adapters/metabase/types.d.ts +1 -1
- package/dist/context/ingest/adapters/metabase/types.js +1 -1
- package/dist/context/ingest/artifact-gates.d.ts +32 -1
- package/dist/context/ingest/artifact-gates.js +85 -18
- package/dist/context/ingest/final-gate-prune.d.ts +35 -0
- package/dist/context/ingest/final-gate-prune.js +229 -0
- package/dist/context/ingest/ingest-bundle.runner.d.ts +3 -0
- package/dist/context/ingest/ingest-bundle.runner.js +459 -240
- package/dist/context/ingest/isolated-diff/patch-integrator.d.ts +0 -11
- package/dist/context/ingest/isolated-diff/patch-integrator.js +0 -44
- package/dist/context/ingest/isolated-diff/work-unit-executor.d.ts +1 -0
- package/dist/context/ingest/isolated-diff/work-unit-executor.js +13 -4
- package/dist/context/ingest/local-adapters.js +6 -0
- package/dist/context/ingest/local-bundle-runtime.js +7 -2
- package/dist/context/ingest/local-ingest.js +1 -1
- package/dist/context/ingest/local-stage-ingest.d.ts +3 -1
- package/dist/context/ingest/local-stage-ingest.js +3 -1
- package/dist/context/ingest/ports.d.ts +3 -0
- package/dist/context/ingest/report-snapshot.js +13 -3
- package/dist/context/ingest/reports.d.ts +3 -3
- package/dist/context/ingest/reports.js +3 -1
- package/dist/context/ingest/stages/build-wu-context.d.ts +1 -0
- package/dist/context/ingest/stages/build-wu-context.js +2 -1
- package/dist/context/ingest/stages/stage-3-work-units.d.ts +2 -1
- package/dist/context/ingest/stages/stage-3-work-units.js +4 -10
- package/dist/context/ingest/stages/validate-wu-sources.d.ts +12 -0
- package/dist/context/ingest/stages/validate-wu-sources.js +23 -8
- package/dist/context/ingest/tools/read-raw-file.tool.js +10 -5
- package/dist/context/ingest/tools/read-raw-span.tool.js +10 -5
- package/dist/context/ingest/tools/warehouse-verification/discover-data.tool.js +1 -1
- package/dist/context/ingest/tools/warehouse-verification/entity-details.tool.js +1 -1
- package/dist/context/ingest/tools/warehouse-verification/sql-execution.tool.js +1 -1
- package/dist/context/ingest/types.d.ts +3 -0
- package/dist/context/ingest/wiki-body-refs.d.ts +28 -0
- package/dist/context/ingest/wiki-body-refs.js +37 -8
- package/dist/context/ingest/wiki-sl-ref-repair.d.ts +1 -0
- package/dist/context/ingest/wiki-sl-ref-repair.js +4 -0
- package/dist/context/ingest/work-unit-cache.d.ts +67 -0
- package/dist/context/ingest/work-unit-cache.js +230 -0
- package/dist/context/llm/ai-sdk-runtime.d.ts +1 -0
- package/dist/context/llm/ai-sdk-runtime.js +5 -0
- package/dist/context/llm/claude-code-runtime.d.ts +4 -1
- package/dist/context/llm/claude-code-runtime.js +38 -8
- package/dist/context/llm/codex-runtime.d.ts +4 -1
- package/dist/context/llm/codex-runtime.js +48 -35
- package/dist/context/llm/runtime-port.d.ts +26 -0
- package/dist/context/llm/subprocess-generate-object-child.d.ts +1 -0
- package/dist/context/llm/subprocess-generate-object-child.js +34 -0
- package/dist/context/llm/subprocess-generate-object.d.ts +42 -0
- package/dist/context/llm/subprocess-generate-object.js +122 -0
- package/dist/context/mcp/context-tools.d.ts +2 -0
- package/dist/context/mcp/context-tools.js +111 -17
- package/dist/context/mcp/local-project-ports.d.ts +7 -0
- package/dist/context/mcp/local-project-ports.js +29 -0
- package/dist/context/mcp/logger.d.ts +24 -0
- package/dist/context/mcp/logger.js +49 -0
- package/dist/context/mcp/server.js +2 -0
- package/dist/context/mcp/types.d.ts +17 -0
- package/dist/context/memory/memory-agent.service.js +1 -1
- package/dist/context/project/config.d.ts +42 -0
- package/dist/context/project/config.js +5 -0
- package/dist/context/project/driver-schemas.d.ts +20 -0
- package/dist/context/project/driver-schemas.js +50 -1
- package/dist/context/project/project.js +1 -1
- package/dist/context/project/setup-config.js +1 -0
- package/dist/context/scan/description-generation.d.ts +4 -0
- package/dist/context/scan/description-generation.js +100 -13
- package/dist/context/scan/enabled-tables.d.ts +5 -0
- package/dist/context/scan/enabled-tables.js +13 -1
- package/dist/context/scan/enrichment-state.d.ts +50 -7
- package/dist/context/scan/enrichment-state.js +30 -13
- package/dist/context/scan/local-enrichment-artifacts.d.ts +41 -0
- package/dist/context/scan/local-enrichment-artifacts.js +155 -32
- package/dist/context/scan/local-enrichment.d.ts +39 -4
- package/dist/context/scan/local-enrichment.js +345 -92
- package/dist/context/scan/local-scan.d.ts +4 -1
- package/dist/context/scan/local-scan.js +54 -13
- package/dist/context/scan/local-structural-artifacts.d.ts +3 -1
- package/dist/context/scan/local-structural-artifacts.js +5 -0
- package/dist/context/scan/object-introspection.d.ts +21 -0
- package/dist/context/scan/object-introspection.js +35 -0
- package/dist/context/scan/relationship-benchmarks.js +5 -3
- package/dist/context/scan/relationship-composite-candidates.d.ts +6 -3
- package/dist/context/scan/relationship-composite-candidates.js +13 -1
- package/dist/context/scan/relationship-detection-budget.d.ts +35 -0
- package/dist/context/scan/relationship-detection-budget.js +53 -0
- package/dist/context/scan/relationship-diagnostics.d.ts +5 -0
- package/dist/context/scan/relationship-diagnostics.js +2 -0
- package/dist/context/scan/relationship-discovery.d.ts +9 -3
- package/dist/context/scan/relationship-discovery.js +27 -4
- package/dist/context/scan/relationship-llm-proposal.js +36 -27
- package/dist/context/scan/relationship-profiling.d.ts +7 -3
- package/dist/context/scan/relationship-profiling.js +53 -41
- package/dist/context/scan/relationship-validation.d.ts +6 -4
- package/dist/context/scan/relationship-validation.js +46 -32
- package/dist/context/scan/sqlite-local-enrichment-state-store.d.ts +8 -1
- package/dist/context/scan/sqlite-local-enrichment-state-store.js +71 -159
- package/dist/context/scan/types.d.ts +5 -3
- package/dist/context/scan/types.js +2 -0
- package/dist/context/sl/local-query.js +5 -0
- package/dist/context/sl/pglite-sl-search-prototype.js +1 -1
- package/dist/context/sl/semantic-layer.service.js +1 -1
- package/dist/context/sl/source-files.d.ts +5 -0
- package/dist/context/sl/source-files.js +17 -11
- package/dist/context/sl/tools/connection-id-schema.js +1 -1
- package/dist/context/sql-analysis/dialect-notes.d.ts +9 -0
- package/dist/context/sql-analysis/dialect-notes.js +40 -0
- package/dist/context/sql-analysis/dialects/bigquery.md +13 -0
- package/dist/context/sql-analysis/dialects/clickhouse.md +9 -0
- package/dist/context/sql-analysis/dialects/mysql.md +9 -0
- package/dist/context/sql-analysis/dialects/postgres.md +10 -0
- package/dist/context/sql-analysis/dialects/snowflake.md +10 -0
- package/dist/context/sql-analysis/dialects/sqlite.md +11 -0
- package/dist/context/sql-analysis/dialects/tsql.md +10 -0
- package/dist/context/wiki/keys.js +1 -1
- package/dist/context/wiki/knowledge-wiki.service.d.ts +4 -4
- package/dist/context/wiki/knowledge-wiki.service.js +2 -1
- package/dist/context/wiki/local-knowledge.d.ts +13 -0
- package/dist/context/wiki/local-knowledge.js +50 -6
- package/dist/context/wiki/sqlite-knowledge-index.d.ts +2 -0
- package/dist/context/wiki/sqlite-knowledge-index.js +21 -5
- package/dist/context/wiki/tools/wiki-write.tool.d.ts +2 -0
- package/dist/context/wiki/tools/wiki-write.tool.js +27 -0
- package/dist/context/wiki/types.d.ts +6 -0
- package/dist/context-build-view.d.ts +3 -0
- package/dist/context-build-view.js +1 -0
- package/dist/knowledge.d.ts +2 -0
- package/dist/knowledge.js +12 -1
- package/dist/local-adapters.js +11 -0
- package/dist/mcp-http-server.js +15 -1
- package/dist/mcp-server-factory.d.ts +2 -0
- package/dist/mcp-server-factory.js +15 -1
- package/dist/mcp-stdio-server.js +10 -2
- package/dist/notion-page-picker.js +1 -1
- package/dist/prompts/memory_agent_external_ingest.md +2 -0
- package/dist/public-ingest.d.ts +3 -1
- package/dist/public-ingest.js +3 -0
- package/dist/scan.d.ts +3 -1
- package/dist/scan.js +7 -0
- package/dist/setup-databases.d.ts +1 -1
- package/dist/setup-databases.js +43 -1
- package/dist/setup-sources.d.ts +5 -1
- package/dist/setup-sources.js +124 -48
- package/dist/setup.d.ts +3 -0
- package/dist/setup.js +6 -1
- package/dist/skills/analytics/SKILL.md +200 -2
- package/dist/skills/gdrive_synthesize/SKILL.md +97 -0
- package/dist/skills/wiki_capture/SKILL.md +24 -0
- package/dist/sql.js +4 -0
- package/dist/status-project.d.ts +4 -0
- package/dist/status-project.js +54 -2
- package/dist/telemetry/events.d.ts +2 -2
- package/dist/text-ingest.d.ts +4 -0
- package/dist/text-ingest.js +58 -29
- package/dist/verbatim-ingest.d.ts +46 -0
- package/dist/verbatim-ingest.js +193 -0
- package/package.json +5 -1
- package/dist/context/ingest/final-gate-repair.d.ts +0 -28
- package/dist/context/ingest/final-gate-repair.js +0 -91
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { basename, extname, join } from 'node:path';
|
|
2
|
+
import YAML from 'yaml';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { noopLogger } from './context/core/config.js';
|
|
5
|
+
import { assertConfiguredConnectionId } from './context/connections/configured-connections.js';
|
|
6
|
+
import { KtxIngestEmbeddingPortAdapter } from './context/llm/embedding-port.js';
|
|
7
|
+
import { createLocalKtxEmbeddingProviderFromConfig, createLocalKtxLlmRuntimeFromConfig } from './context/llm/local-config.js';
|
|
8
|
+
import { KnowledgeWikiService } from './context/wiki/knowledge-wiki.service.js';
|
|
9
|
+
import { suggestFlatWikiKey } from './context/wiki/keys.js';
|
|
10
|
+
import { SqliteKnowledgeIndex } from './context/wiki/sqlite-knowledge-index.js';
|
|
11
|
+
const LOCAL_AUTHOR = 'ktx';
|
|
12
|
+
const LOCAL_AUTHOR_EMAIL = 'ktx@example.com';
|
|
13
|
+
/** Only the prefix sent to the LLM for metadata is clipped; the stored body is never clipped. */
|
|
14
|
+
const METADATA_CLIP_LENGTH = 48_000;
|
|
15
|
+
const VERBATIM_METADATA_SYSTEM_PROMPT = [
|
|
16
|
+
'You generate search metadata for an authoritative document that ktx stores verbatim.',
|
|
17
|
+
'You never rewrite, summarize into, or alter the document body — you only describe it.',
|
|
18
|
+
'Return a concise one- or two-sentence summary, a few topical tags, and any semantic-layer',
|
|
19
|
+
'source names the document is clearly about. Use empty arrays when none apply.',
|
|
20
|
+
].join(' ');
|
|
21
|
+
const verbatimMetadataSchema = z.object({
|
|
22
|
+
summary: z.string().min(1).describe('A one- or two-sentence description of what the document defines or specifies.'),
|
|
23
|
+
tags: z.array(z.string()).default([]).describe('Short topical keywords that aid lexical and semantic recall.'),
|
|
24
|
+
sl_refs: z
|
|
25
|
+
.array(z.string())
|
|
26
|
+
.default([])
|
|
27
|
+
.describe('Semantic-layer source names the document is clearly about, if any are evident.'),
|
|
28
|
+
});
|
|
29
|
+
const DEGRADED_SUMMARY_MAX_LENGTH = 200;
|
|
30
|
+
const FRONTMATTER_PATTERN = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/;
|
|
31
|
+
const HEADING_PATTERN = /^#{1,6}\s+(.+?)\s*#*\s*$/;
|
|
32
|
+
function isUsageMode(value) {
|
|
33
|
+
return value === 'always' || value === 'auto' || value === 'never';
|
|
34
|
+
}
|
|
35
|
+
function nonEmptyString(value) {
|
|
36
|
+
return typeof value === 'string' && value.trim().length > 0 ? value : undefined;
|
|
37
|
+
}
|
|
38
|
+
function stringArray(value) {
|
|
39
|
+
return Array.isArray(value) ? value.filter((item) => typeof item === 'string') : [];
|
|
40
|
+
}
|
|
41
|
+
/** `connections` accepts a single id or a list in YAML; normalize either to a string list. */
|
|
42
|
+
function stringList(value) {
|
|
43
|
+
if (typeof value === 'string') {
|
|
44
|
+
return value.trim().length > 0 ? [value] : [];
|
|
45
|
+
}
|
|
46
|
+
return stringArray(value);
|
|
47
|
+
}
|
|
48
|
+
function leadingHeadingText(body) {
|
|
49
|
+
const firstLine = body.trimStart().split('\n', 1)[0] ?? '';
|
|
50
|
+
const match = firstLine.match(HEADING_PATTERN);
|
|
51
|
+
return match ? match[1].trim() : null;
|
|
52
|
+
}
|
|
53
|
+
/** @internal */
|
|
54
|
+
export function splitInputDocument(raw) {
|
|
55
|
+
const match = raw.match(FRONTMATTER_PATTERN);
|
|
56
|
+
if (!match) {
|
|
57
|
+
return { frontmatter: {}, body: raw.trim() };
|
|
58
|
+
}
|
|
59
|
+
const parsed = YAML.parse(match[1]);
|
|
60
|
+
const frontmatter = parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)
|
|
61
|
+
? parsed
|
|
62
|
+
: {};
|
|
63
|
+
return { frontmatter, body: match[2].trim() };
|
|
64
|
+
}
|
|
65
|
+
/** @internal */
|
|
66
|
+
export function deriveVerbatimPageKey(origin, body) {
|
|
67
|
+
if (origin.kind === 'file' && origin.path) {
|
|
68
|
+
return suggestFlatWikiKey(basename(origin.path, extname(origin.path)));
|
|
69
|
+
}
|
|
70
|
+
const heading = leadingHeadingText(body);
|
|
71
|
+
if (!heading) {
|
|
72
|
+
throw new Error('Verbatim inline text needs a leading Markdown heading to derive a stable page key. Add a "# Heading" line, or pass the content as --file <path>.');
|
|
73
|
+
}
|
|
74
|
+
return suggestFlatWikiKey(heading);
|
|
75
|
+
}
|
|
76
|
+
/** @internal */
|
|
77
|
+
export function deriveDegradedSummary(body) {
|
|
78
|
+
const heading = leadingHeadingText(body);
|
|
79
|
+
if (heading) {
|
|
80
|
+
return heading;
|
|
81
|
+
}
|
|
82
|
+
const text = body.trim();
|
|
83
|
+
const sentence = text.match(/^([\s\S]*?[.!?])(\s|$)/);
|
|
84
|
+
const summary = sentence ? sentence[1].trim() : text;
|
|
85
|
+
if (summary.length <= DEGRADED_SUMMARY_MAX_LENGTH) {
|
|
86
|
+
return summary;
|
|
87
|
+
}
|
|
88
|
+
return `${summary.slice(0, DEGRADED_SUMMARY_MAX_LENGTH).trimEnd()}…`;
|
|
89
|
+
}
|
|
90
|
+
/** @internal */
|
|
91
|
+
export function buildVerbatimFrontmatter(input) {
|
|
92
|
+
const { inputFrontmatter } = input;
|
|
93
|
+
const inputConnections = stringList(inputFrontmatter.connections);
|
|
94
|
+
const flagConnections = input.connectionId ? [input.connectionId] : [];
|
|
95
|
+
if (inputConnections.length > 0 &&
|
|
96
|
+
flagConnections.length > 0 &&
|
|
97
|
+
!connectionSetsEqual(inputConnections, flagConnections)) {
|
|
98
|
+
throw new Error(`Connection scope conflict: frontmatter declares connections [${inputConnections.join(', ')}] but --connection-id is "${input.connectionId}". Remove one so the intent is unambiguous.`);
|
|
99
|
+
}
|
|
100
|
+
const connections = inputConnections.length > 0 ? inputConnections : flagConnections;
|
|
101
|
+
const summary = nonEmptyString(inputFrontmatter.summary) ?? input.summary;
|
|
102
|
+
const usageMode = isUsageMode(inputFrontmatter.usage_mode) ? inputFrontmatter.usage_mode : 'auto';
|
|
103
|
+
const tags = inputFrontmatter.tags !== undefined ? stringArray(inputFrontmatter.tags) : input.tags;
|
|
104
|
+
const slRefs = inputFrontmatter.sl_refs !== undefined ? stringArray(inputFrontmatter.sl_refs) : input.slRefs;
|
|
105
|
+
const passthrough = Object.fromEntries(Object.entries(inputFrontmatter).filter(([key]) => !['summary', 'usage_mode', 'tags', 'sl_refs', 'connections'].includes(key)));
|
|
106
|
+
return {
|
|
107
|
+
...passthrough,
|
|
108
|
+
summary,
|
|
109
|
+
usage_mode: usageMode,
|
|
110
|
+
...(tags.length > 0 ? { tags } : {}),
|
|
111
|
+
...(slRefs.length > 0 ? { sl_refs: slRefs } : {}),
|
|
112
|
+
...(connections.length > 0 ? { connections } : {}),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function connectionSetsEqual(left, right) {
|
|
116
|
+
if (left.length !== right.length) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
const rightSet = new Set(right);
|
|
120
|
+
return left.every((id) => rightSet.has(id));
|
|
121
|
+
}
|
|
122
|
+
class LocalVerbatimIngestor {
|
|
123
|
+
deps;
|
|
124
|
+
constructor(deps) {
|
|
125
|
+
this.deps = deps;
|
|
126
|
+
}
|
|
127
|
+
async ingest(item) {
|
|
128
|
+
if (item.connectionId) {
|
|
129
|
+
assertConfiguredConnectionId(this.deps.configuredConnections, item.connectionId);
|
|
130
|
+
}
|
|
131
|
+
const { frontmatter: inputFrontmatter, body } = splitInputDocument(item.content);
|
|
132
|
+
const pageKey = deriveVerbatimPageKey(item.origin, body);
|
|
133
|
+
const generated = await this.resolveMetadata(inputFrontmatter, body);
|
|
134
|
+
const frontmatter = buildVerbatimFrontmatter({
|
|
135
|
+
inputFrontmatter,
|
|
136
|
+
summary: generated.summary,
|
|
137
|
+
tags: generated.tags,
|
|
138
|
+
slRefs: generated.slRefs,
|
|
139
|
+
...(item.connectionId ? { connectionId: item.connectionId } : {}),
|
|
140
|
+
});
|
|
141
|
+
const connections = Array.isArray(frontmatter.connections) ? frontmatter.connections : [];
|
|
142
|
+
const existing = await this.deps.wikiService.readPage('GLOBAL', null, pageKey);
|
|
143
|
+
if (existing) {
|
|
144
|
+
if (existing.content === body) {
|
|
145
|
+
return { pageKey, outcome: 'unchanged', connections, commitHash: null };
|
|
146
|
+
}
|
|
147
|
+
throw new Error(`A different page already exists at key "${pageKey}". Re-run with a distinct document name or key, ` +
|
|
148
|
+
'or remove the existing page first — verbatim ingest never overwrites a conflicting page.');
|
|
149
|
+
}
|
|
150
|
+
const writeResult = await this.deps.wikiService.writePageAndSync('GLOBAL', null, pageKey, frontmatter, body, this.deps.author, this.deps.authorEmail, `Ingest verbatim document: ${pageKey}`);
|
|
151
|
+
return { pageKey, outcome: 'written', connections, commitHash: writeResult.commitHash ?? null };
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Generated metadata is only used to gap-fill absent frontmatter fields, so the LLM is
|
|
155
|
+
* skipped entirely when summary, tags, and sl_refs are all explicit. A configured backend
|
|
156
|
+
* that fails surfaces the error (the item fails); degraded derivation is reserved for
|
|
157
|
+
* `backend: none`, never used as a silent fallback that would poison the idempotency check.
|
|
158
|
+
*/
|
|
159
|
+
async resolveMetadata(inputFrontmatter, body) {
|
|
160
|
+
const needsGeneration = nonEmptyString(inputFrontmatter.summary) === undefined ||
|
|
161
|
+
inputFrontmatter.tags === undefined ||
|
|
162
|
+
inputFrontmatter.sl_refs === undefined;
|
|
163
|
+
if (this.deps.llmRuntime && needsGeneration) {
|
|
164
|
+
const clipped = body.length > METADATA_CLIP_LENGTH ? body.slice(0, METADATA_CLIP_LENGTH) : body;
|
|
165
|
+
const generated = await this.deps.llmRuntime.generateObject({
|
|
166
|
+
role: 'triage',
|
|
167
|
+
system: VERBATIM_METADATA_SYSTEM_PROMPT,
|
|
168
|
+
prompt: clipped,
|
|
169
|
+
schema: verbatimMetadataSchema,
|
|
170
|
+
});
|
|
171
|
+
return { summary: generated.summary, tags: generated.tags, slRefs: generated.sl_refs };
|
|
172
|
+
}
|
|
173
|
+
return { summary: deriveDegradedSummary(body), tags: [], slRefs: [] };
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
export function createLocalProjectVerbatimIngestor(project, deps = {}) {
|
|
177
|
+
const llmRuntime = deps.llmRuntime !== undefined
|
|
178
|
+
? deps.llmRuntime
|
|
179
|
+
: createLocalKtxLlmRuntimeFromConfig(project.config.llm, { projectDir: project.projectDir });
|
|
180
|
+
const embeddingProvider = deps.embeddingProvider !== undefined
|
|
181
|
+
? deps.embeddingProvider
|
|
182
|
+
: createLocalKtxEmbeddingProviderFromConfig(project.config.ingest.embeddings, { projectDir: project.projectDir });
|
|
183
|
+
const embeddingPort = embeddingProvider ? new KtxIngestEmbeddingPortAdapter(embeddingProvider) : null;
|
|
184
|
+
const knowledgeIndex = new SqliteKnowledgeIndex({ dbPath: join(project.projectDir, '.ktx', 'db.sqlite') });
|
|
185
|
+
const wikiService = new KnowledgeWikiService(project.fileStore, embeddingPort, knowledgeIndex, project.git, noopLogger);
|
|
186
|
+
return new LocalVerbatimIngestor({
|
|
187
|
+
wikiService,
|
|
188
|
+
llmRuntime,
|
|
189
|
+
configuredConnections: project.config.connections,
|
|
190
|
+
author: LOCAL_AUTHOR,
|
|
191
|
+
authorEmail: LOCAL_AUTHOR_EMAIL,
|
|
192
|
+
});
|
|
193
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kaelio/ktx",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Standalone ktx context layer for data agents",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Kaelio",
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
"@commander-js/extra-typings": "14.0.0",
|
|
43
43
|
"@duckdb/node-api": "1.5.3-r.3",
|
|
44
44
|
"@google-cloud/bigquery": "^8.3.1",
|
|
45
|
+
"google-auth-library": "10.6.2",
|
|
45
46
|
"@looker/sdk": "^26.8.0",
|
|
46
47
|
"@looker/sdk-node": "^26.8.0",
|
|
47
48
|
"@looker/sdk-rtl": "^21.6.5",
|
|
@@ -56,11 +57,14 @@
|
|
|
56
57
|
"ink": "^7.0.3",
|
|
57
58
|
"lookml-parser": "7.1.0",
|
|
58
59
|
"minimatch": "^10.2.5",
|
|
60
|
+
"mongodb": "^6.12.0",
|
|
59
61
|
"mssql": "^12.5.4",
|
|
60
62
|
"mysql2": "^3.22.3",
|
|
61
63
|
"openai": "^6.38.0",
|
|
62
64
|
"p-limit": "^7.3.0",
|
|
63
65
|
"pg": "^8.21.0",
|
|
66
|
+
"pino": "^10.3.1",
|
|
67
|
+
"pino-pretty": "^13.1.3",
|
|
64
68
|
"posthog-node": "^5.34.9",
|
|
65
69
|
"react": "^19.2.6",
|
|
66
70
|
"semver": "^7.8.1",
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { AgentRunnerPort } from '../../context/llm/runtime-port.js';
|
|
2
|
-
import type { ConstrainedRepairResult, RepairVerification } from './constrained-repair.js';
|
|
3
|
-
import type { IngestTraceWriter } from './ingest-trace.js';
|
|
4
|
-
type FinalGateRepairKind = 'patch_semantic_gate' | 'final_artifact_gate';
|
|
5
|
-
export type FinalGateRepairResult = ConstrainedRepairResult;
|
|
6
|
-
export interface RepairFinalGateFailureInput {
|
|
7
|
-
agentRunner: AgentRunnerPort;
|
|
8
|
-
workdir: string;
|
|
9
|
-
gateError: string;
|
|
10
|
-
allowedPaths: string[];
|
|
11
|
-
trace: IngestTraceWriter;
|
|
12
|
-
repairKind: FinalGateRepairKind;
|
|
13
|
-
/**
|
|
14
|
-
* Re-runs the failed gate against the current worktree. The repair counts
|
|
15
|
-
* as successful only when this passes — editing files is not the success
|
|
16
|
-
* signal.
|
|
17
|
-
*/
|
|
18
|
-
verify(changedPaths: string[]): Promise<RepairVerification>;
|
|
19
|
-
maxAttempts?: number;
|
|
20
|
-
stepBudget?: number;
|
|
21
|
-
abortSignal?: AbortSignal;
|
|
22
|
-
}
|
|
23
|
-
export declare function finalGateRepairPaths(input: {
|
|
24
|
-
changedWikiPageKeys: string[];
|
|
25
|
-
touchedSlSourcePaths: string[];
|
|
26
|
-
}): string[];
|
|
27
|
-
export declare function repairFinalGateFailure(input: RepairFinalGateFailureInput): Promise<FinalGateRepairResult>;
|
|
28
|
-
export {};
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { runConstrainedRepairLoop } from './constrained-repair.js';
|
|
3
|
-
function buildGateRepairSystemPrompt() {
|
|
4
|
-
return `<role>
|
|
5
|
-
You repair one ktx isolated-diff artifact gate failure inside the integration worktree.
|
|
6
|
-
</role>
|
|
7
|
-
|
|
8
|
-
<rules>
|
|
9
|
-
- Use read_gate_error first.
|
|
10
|
-
- Read only files exposed by read_repair_file.
|
|
11
|
-
- Edit only paths exposed by write_repair_file.
|
|
12
|
-
- Prefer the smallest text edit that makes the gate pass.
|
|
13
|
-
- Preserve accepted work-unit, reconciliation, and deterministic projection content.
|
|
14
|
-
- Do not invent warehouse facts, business definitions, or semantic-layer entities.
|
|
15
|
-
- If the gate error requires choosing between conflicting facts without evidence, stop without editing.
|
|
16
|
-
</rules>`;
|
|
17
|
-
}
|
|
18
|
-
function buildGateRepairUserPrompt(input) {
|
|
19
|
-
const previousFailureBlock = input.previousFailure
|
|
20
|
-
? `\nPrevious attempt did not pass the gate:\n${input.previousFailure}\n`
|
|
21
|
-
: '';
|
|
22
|
-
return `Repair isolated-diff artifact gates.
|
|
23
|
-
|
|
24
|
-
Repair kind: ${input.repairKind}
|
|
25
|
-
Attempt: ${input.attempt} of ${input.maxAttempts}
|
|
26
|
-
|
|
27
|
-
Allowed files:
|
|
28
|
-
${input.allowedPaths.map((path) => `- ${path}`).join('\n')}
|
|
29
|
-
|
|
30
|
-
Gate error:
|
|
31
|
-
${input.gateError}
|
|
32
|
-
${previousFailureBlock}
|
|
33
|
-
Use read_gate_error first. Then inspect only the allowed files, write the
|
|
34
|
-
minimal repaired content, and stop.`;
|
|
35
|
-
}
|
|
36
|
-
function buildReadGateErrorTool(gateError) {
|
|
37
|
-
return {
|
|
38
|
-
read_gate_error: {
|
|
39
|
-
name: 'read_gate_error',
|
|
40
|
-
description: 'Read the artifact gate failure that must be repaired.',
|
|
41
|
-
inputSchema: z.object({}),
|
|
42
|
-
execute: async () => ({
|
|
43
|
-
markdown: gateError,
|
|
44
|
-
structured: { gateError },
|
|
45
|
-
}),
|
|
46
|
-
},
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
export function finalGateRepairPaths(input) {
|
|
50
|
-
return [
|
|
51
|
-
...new Set([
|
|
52
|
-
...input.touchedSlSourcePaths,
|
|
53
|
-
...input.changedWikiPageKeys.map((pageKey) => `wiki/global/${pageKey}.md`),
|
|
54
|
-
]),
|
|
55
|
-
].sort();
|
|
56
|
-
}
|
|
57
|
-
export async function repairFinalGateFailure(input) {
|
|
58
|
-
return runConstrainedRepairLoop({
|
|
59
|
-
agentRunner: input.agentRunner,
|
|
60
|
-
workdir: input.workdir,
|
|
61
|
-
allowedPaths: input.allowedPaths,
|
|
62
|
-
trace: input.trace,
|
|
63
|
-
tracePhase: 'gate_repair',
|
|
64
|
-
traceEventName: 'gate_repair',
|
|
65
|
-
traceData: {
|
|
66
|
-
repairKind: input.repairKind,
|
|
67
|
-
gateError: input.gateError,
|
|
68
|
-
},
|
|
69
|
-
systemPrompt: buildGateRepairSystemPrompt(),
|
|
70
|
-
buildUserPrompt: ({ attempt, maxAttempts, previousFailure }) => buildGateRepairUserPrompt({
|
|
71
|
-
gateError: input.gateError,
|
|
72
|
-
allowedPaths: [...input.allowedPaths].sort(),
|
|
73
|
-
repairKind: input.repairKind,
|
|
74
|
-
attempt,
|
|
75
|
-
maxAttempts,
|
|
76
|
-
previousFailure,
|
|
77
|
-
}),
|
|
78
|
-
buildExtraTools: () => buildReadGateErrorTool(input.gateError),
|
|
79
|
-
verify: input.verify,
|
|
80
|
-
noChangeFailureReason: 'gate repair completed without editing an allowed path',
|
|
81
|
-
telemetryTags: {
|
|
82
|
-
operationName: 'ingest-isolated-diff-gate-repair',
|
|
83
|
-
source: input.trace.context.sourceKey,
|
|
84
|
-
jobId: input.trace.context.jobId,
|
|
85
|
-
repairKind: input.repairKind,
|
|
86
|
-
},
|
|
87
|
-
maxAttempts: input.maxAttempts,
|
|
88
|
-
stepBudget: input.stepBudget ?? 16,
|
|
89
|
-
abortSignal: input.abortSignal,
|
|
90
|
-
});
|
|
91
|
-
}
|