@kaelio/ktx 0.13.1 → 0.15.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.1-py3-none-any.whl → kaelio_ktx-0.15.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 +15 -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 +20 -3
- 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/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/adapters/sigma/chunk.d.ts +6 -0
- package/dist/context/ingest/adapters/sigma/chunk.js +119 -0
- package/dist/context/ingest/adapters/sigma/client-port.d.ts +45 -0
- package/dist/context/ingest/adapters/sigma/client-port.js +1 -0
- package/dist/context/ingest/adapters/sigma/client.d.ts +33 -0
- package/dist/context/ingest/adapters/sigma/client.js +176 -0
- package/dist/context/ingest/adapters/sigma/detect.d.ts +1 -0
- package/dist/context/ingest/adapters/sigma/detect.js +23 -0
- package/dist/context/ingest/adapters/sigma/fetch.d.ts +14 -0
- package/dist/context/ingest/adapters/sigma/fetch.js +191 -0
- package/dist/context/ingest/adapters/sigma/local-sigma.adapter.d.ts +17 -0
- package/dist/context/ingest/adapters/sigma/local-sigma.adapter.js +41 -0
- package/dist/context/ingest/adapters/sigma/project.d.ts +8 -0
- package/dist/context/ingest/adapters/sigma/project.js +186 -0
- package/dist/context/ingest/adapters/sigma/sigma.adapter.d.ts +18 -0
- package/dist/context/ingest/adapters/sigma/sigma.adapter.js +43 -0
- package/dist/context/ingest/adapters/sigma/types.d.ts +80 -0
- package/dist/context/ingest/adapters/sigma/types.js +82 -0
- 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.d.ts +2 -1
- package/dist/context/ingest/local-adapters.js +28 -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 +72 -0
- package/dist/context/project/config.js +5 -0
- package/dist/context/project/driver-schemas.d.ts +35 -0
- package/dist/context/project/driver-schemas.js +89 -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 +4 -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 +6 -1
- package/dist/setup-sources.js +208 -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/sigma_ingest/SKILL.md +189 -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
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { KtxExpectedError, KtxQueryError, isNativeProgrammingFault } from '../../errors.js';
|
|
2
|
+
import { isDatabaseDriver, normalizeConnectionDriver } from '../../connection-drivers.js';
|
|
3
|
+
import { sqlDialectNotes } from '../../context/sql-analysis/dialect-notes.js';
|
|
2
4
|
import { executeProjectReadOnlySql } from '../../context/connections/project-sql-executor.js';
|
|
3
5
|
import { FEDERATED_CONNECTION_ID, federatedConnectionListing } from '../../context/connections/federation.js';
|
|
6
|
+
import { assertSqlQueryableConnection } from '../../context/connections/dialects.js';
|
|
4
7
|
import { resolveConfiguredConnection } from '../../context/connections/resolve-connection.js';
|
|
5
8
|
import { localConnectionInfoFromConfig, } from '../../context/connections/local-warehouse-descriptor.js';
|
|
6
9
|
import { createKtxEntityDetailsService } from '../../context/scan/entity-details.js';
|
|
@@ -10,6 +13,7 @@ import { compileLocalSlQuery } from '../../context/sl/local-query.js';
|
|
|
10
13
|
import { createKtxDictionarySearchService } from '../../context/sl/dictionary-search.js';
|
|
11
14
|
import { readLocalSlSource } from '../../context/sl/local-sl.js';
|
|
12
15
|
import { assertSafeConnectionId } from '../../context/sl/source-files.js';
|
|
16
|
+
import { assertConfiguredConnectionId } from '../../context/connections/configured-connections.js';
|
|
13
17
|
import { readLocalKnowledgePage, searchLocalKnowledgePages } from '../wiki/local-knowledge.js';
|
|
14
18
|
async function executeValidatedReadOnlySql(project, options, input, onProgress) {
|
|
15
19
|
await onProgress?.({ progress: 0, message: 'Validating SQL' });
|
|
@@ -23,6 +27,9 @@ async function executeValidatedReadOnlySql(project, options, input, onProgress)
|
|
|
23
27
|
const isFederated = input.connectionId === FEDERATED_CONNECTION_ID;
|
|
24
28
|
const connectionId = isFederated ? input.connectionId : assertSafeConnectionId(input.connectionId);
|
|
25
29
|
const connection = isFederated ? undefined : resolveConfiguredConnection(project.config, connectionId);
|
|
30
|
+
if (!isFederated) {
|
|
31
|
+
assertSqlQueryableConnection(connectionId, connection.driver);
|
|
32
|
+
}
|
|
26
33
|
const dialect = sqlAnalysisDialectForDriver(isFederated ? 'duckdb' : connection.driver);
|
|
27
34
|
const validation = await options.sqlAnalysis.validateReadOnly(input.sql, dialect);
|
|
28
35
|
if (!validation.ok) {
|
|
@@ -62,6 +69,18 @@ async function executeValidatedReadOnlySql(project, options, input, onProgress)
|
|
|
62
69
|
await onProgress?.({ progress: 1, message: `Fetched ${response.rowCount} rows` });
|
|
63
70
|
return response;
|
|
64
71
|
}
|
|
72
|
+
/** @internal Resolves a connection's dialect SQL notes; throws KtxExpectedError for an unknown or non-SQL-warehouse connection. */
|
|
73
|
+
export function resolveDialectNotesForConnection(connectionId, connection) {
|
|
74
|
+
if (!connection) {
|
|
75
|
+
throw new KtxExpectedError(`Connection "${connectionId}" is not configured in ktx.yaml`);
|
|
76
|
+
}
|
|
77
|
+
const driver = normalizeConnectionDriver(connection);
|
|
78
|
+
if (!isDatabaseDriver(driver)) {
|
|
79
|
+
throw new KtxExpectedError(`Connection "${connectionId}" uses the "${driver}" context source, not a SQL warehouse; sql_dialect_notes applies only to SQL database connections.`);
|
|
80
|
+
}
|
|
81
|
+
const dialect = sqlAnalysisDialectForDriver(driver);
|
|
82
|
+
return { connectionId, dialect, notes: sqlDialectNotes(dialect) };
|
|
83
|
+
}
|
|
65
84
|
export function createLocalProjectMcpContextPorts(project, options) {
|
|
66
85
|
const embeddingService = options.embeddingService;
|
|
67
86
|
const ports = {
|
|
@@ -86,11 +105,15 @@ export function createLocalProjectMcpContextPorts(project, options) {
|
|
|
86
105
|
},
|
|
87
106
|
knowledge: {
|
|
88
107
|
async search(input) {
|
|
108
|
+
const connectionId = input.connectionId === undefined
|
|
109
|
+
? undefined
|
|
110
|
+
: assertConfiguredConnectionId(project.config.connections, input.connectionId);
|
|
89
111
|
const results = await searchLocalKnowledgePages(project, {
|
|
90
112
|
query: input.query,
|
|
91
113
|
userId: input.userId,
|
|
92
114
|
limit: input.limit,
|
|
93
115
|
embeddingService,
|
|
116
|
+
...(connectionId !== undefined ? { connectionId } : {}),
|
|
94
117
|
});
|
|
95
118
|
return {
|
|
96
119
|
results: results.slice(0, input.limit).map((result) => ({
|
|
@@ -161,6 +184,12 @@ export function createLocalProjectMcpContextPorts(project, options) {
|
|
|
161
184
|
return createKtxDiscoverDataService(project, { userId: 'local', embeddingService }).search(input);
|
|
162
185
|
},
|
|
163
186
|
},
|
|
187
|
+
dialectNotes: {
|
|
188
|
+
async read(input) {
|
|
189
|
+
const connectionId = assertSafeConnectionId(input.connectionId);
|
|
190
|
+
return resolveDialectNotesForConnection(connectionId, project.config.connections[connectionId]);
|
|
191
|
+
},
|
|
192
|
+
},
|
|
164
193
|
};
|
|
165
194
|
if (options.sqlAnalysis && options.localScan?.createConnector) {
|
|
166
195
|
ports.sqlExecution = {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type Logger } from 'pino';
|
|
2
|
+
import type { KtxCliIo } from '../../cli-runtime.js';
|
|
3
|
+
export type KtxMcpLogger = Logger;
|
|
4
|
+
/** @internal */
|
|
5
|
+
export declare function mcpLogLevel(env?: NodeJS.ProcessEnv): string;
|
|
6
|
+
/** @internal */
|
|
7
|
+
export declare function mcpSlowToolMs(env?: NodeJS.ProcessEnv): number;
|
|
8
|
+
/**
|
|
9
|
+
* Serialize an error for a structured `err` field. Genuine `Error`s get pino's
|
|
10
|
+
* standard serializer (type + message + stack); everything else is reduced to a
|
|
11
|
+
* message — the in-band tool-error path has already lost the original stack.
|
|
12
|
+
*/
|
|
13
|
+
export declare function serializeMcpError(error: unknown): Record<string, unknown>;
|
|
14
|
+
/**
|
|
15
|
+
* One synchronous pino logger per MCP server process, written to the `io.stderr`
|
|
16
|
+
* sink. stderr is the only universally-correct sink: the stdio transport reserves
|
|
17
|
+
* stdout for JSON-RPC, and the HTTP daemon redirects stderr into `.ktx/logs/mcp.log`.
|
|
18
|
+
* Synchronous writes are load-bearing — a `tool.start` line must reach the fd before
|
|
19
|
+
* a blocking handler runs, so a runaway query still leaves its start record on disk.
|
|
20
|
+
* Format follows the terminal, not a flag: pretty for a TTY, plain JSON otherwise.
|
|
21
|
+
*/
|
|
22
|
+
export declare function createMcpLogger(io: KtxCliIo, options?: {
|
|
23
|
+
isTTY?: boolean;
|
|
24
|
+
}): KtxMcpLogger;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Writable } from 'node:stream';
|
|
2
|
+
import pino from 'pino';
|
|
3
|
+
import PinoPretty from 'pino-pretty';
|
|
4
|
+
const LOG_LEVELS = new Set(['trace', 'debug', 'info', 'warn', 'error', 'fatal', 'silent']);
|
|
5
|
+
const DEFAULT_LEVEL = 'info';
|
|
6
|
+
const DEFAULT_SLOW_TOOL_MS = 10_000;
|
|
7
|
+
/** @internal */
|
|
8
|
+
export function mcpLogLevel(env = process.env) {
|
|
9
|
+
const raw = env.KTX_MCP_LOG_LEVEL?.trim().toLowerCase();
|
|
10
|
+
return raw && LOG_LEVELS.has(raw) ? raw : DEFAULT_LEVEL;
|
|
11
|
+
}
|
|
12
|
+
/** @internal */
|
|
13
|
+
export function mcpSlowToolMs(env = process.env) {
|
|
14
|
+
const raw = Number(env.KTX_MCP_SLOW_TOOL_MS);
|
|
15
|
+
return Number.isFinite(raw) && raw >= 0 ? raw : DEFAULT_SLOW_TOOL_MS;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Serialize an error for a structured `err` field. Genuine `Error`s get pino's
|
|
19
|
+
* standard serializer (type + message + stack); everything else is reduced to a
|
|
20
|
+
* message — the in-band tool-error path has already lost the original stack.
|
|
21
|
+
*/
|
|
22
|
+
export function serializeMcpError(error) {
|
|
23
|
+
if (error instanceof Error) {
|
|
24
|
+
return { ...pino.stdSerializers.err(error) };
|
|
25
|
+
}
|
|
26
|
+
return { message: typeof error === 'string' ? error : String(error) };
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* One synchronous pino logger per MCP server process, written to the `io.stderr`
|
|
30
|
+
* sink. stderr is the only universally-correct sink: the stdio transport reserves
|
|
31
|
+
* stdout for JSON-RPC, and the HTTP daemon redirects stderr into `.ktx/logs/mcp.log`.
|
|
32
|
+
* Synchronous writes are load-bearing — a `tool.start` line must reach the fd before
|
|
33
|
+
* a blocking handler runs, so a runaway query still leaves its start record on disk.
|
|
34
|
+
* Format follows the terminal, not a flag: pretty for a TTY, plain JSON otherwise.
|
|
35
|
+
*/
|
|
36
|
+
export function createMcpLogger(io, options = {}) {
|
|
37
|
+
const level = mcpLogLevel();
|
|
38
|
+
const isTTY = options.isTTY ?? process.stderr.isTTY === true;
|
|
39
|
+
if (isTTY) {
|
|
40
|
+
const sink = new Writable({
|
|
41
|
+
write(chunk, _encoding, callback) {
|
|
42
|
+
io.stderr.write(typeof chunk === 'string' ? chunk : chunk.toString('utf8'));
|
|
43
|
+
callback();
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
return pino({ level }, PinoPretty({ colorize: true, sync: true, destination: sink }));
|
|
47
|
+
}
|
|
48
|
+
return pino({ level }, io.stderr);
|
|
49
|
+
}
|
|
@@ -9,6 +9,7 @@ export function createKtxMcpServer(deps) {
|
|
|
9
9
|
userContext: deps.userContext,
|
|
10
10
|
projectDir: deps.projectDir,
|
|
11
11
|
io: deps.io,
|
|
12
|
+
logger: deps.logger,
|
|
12
13
|
getClientInfo: deps.getClientInfo,
|
|
13
14
|
});
|
|
14
15
|
}
|
|
@@ -25,6 +26,7 @@ export function createDefaultKtxMcpServer(deps) {
|
|
|
25
26
|
contextTools: deps.contextTools,
|
|
26
27
|
projectDir: deps.projectDir,
|
|
27
28
|
io: deps.io,
|
|
29
|
+
logger: deps.logger,
|
|
28
30
|
// The SDK populates the client identity after the initialize handshake, so
|
|
29
31
|
// read it lazily at emit time rather than at registration (undefined here).
|
|
30
32
|
getClientInfo: () => server.server.getClientVersion(),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { MemoryIngestService } from '../../context/memory/memory-runs.js';
|
|
2
2
|
import type { KtxCliIo } from '../../cli-runtime.js';
|
|
3
|
+
import type { KtxMcpLogger } from './logger.js';
|
|
3
4
|
import type { KtxEntityDetailsInput, KtxEntityDetailsResponse } from '../scan/entity-details.js';
|
|
4
5
|
import type { KtxDiscoverDataInput, KtxDiscoverDataResponse } from '../../context/search/discover.js';
|
|
5
6
|
import type { KtxDictionarySearchInput, KtxDictionarySearchResponse } from '../../context/sl/dictionary-search.js';
|
|
@@ -24,6 +25,8 @@ interface KtxMcpProgressEvent {
|
|
|
24
25
|
}
|
|
25
26
|
export type KtxMcpProgressCallback = (event: KtxMcpProgressEvent) => void | Promise<void>;
|
|
26
27
|
export interface KtxMcpToolHandlerContext {
|
|
28
|
+
/** Present for the HTTP StreamableHTTP transport (one per session); absent for stdio. */
|
|
29
|
+
sessionId?: string;
|
|
27
30
|
_meta?: {
|
|
28
31
|
progressToken?: string | number;
|
|
29
32
|
[key: string]: unknown;
|
|
@@ -102,6 +105,7 @@ export interface KtxKnowledgeMcpPort {
|
|
|
102
105
|
userId: string;
|
|
103
106
|
query: string;
|
|
104
107
|
limit: number;
|
|
108
|
+
connectionId?: string;
|
|
105
109
|
}): Promise<KtxKnowledgeSearchResponse>;
|
|
106
110
|
read(input: {
|
|
107
111
|
userId: string;
|
|
@@ -163,6 +167,16 @@ export interface KtxSqlExecutionMcpPort {
|
|
|
163
167
|
onProgress?: KtxMcpProgressCallback;
|
|
164
168
|
}): Promise<KtxSqlExecutionResponse>;
|
|
165
169
|
}
|
|
170
|
+
/** @internal */
|
|
171
|
+
export interface KtxDialectNotesMcpPort {
|
|
172
|
+
read(input: {
|
|
173
|
+
connectionId: string;
|
|
174
|
+
}): Promise<{
|
|
175
|
+
connectionId: string;
|
|
176
|
+
dialect: string;
|
|
177
|
+
notes: string;
|
|
178
|
+
}>;
|
|
179
|
+
}
|
|
166
180
|
export interface KtxMcpContextPorts {
|
|
167
181
|
connections?: KtxConnectionsMcpPort;
|
|
168
182
|
knowledge?: KtxKnowledgeMcpPort;
|
|
@@ -171,6 +185,7 @@ export interface KtxMcpContextPorts {
|
|
|
171
185
|
dictionarySearch?: KtxDictionarySearchMcpPort;
|
|
172
186
|
discover?: KtxDiscoverDataMcpPort;
|
|
173
187
|
sqlExecution?: KtxSqlExecutionMcpPort;
|
|
188
|
+
dialectNotes?: KtxDialectNotesMcpPort;
|
|
174
189
|
memoryIngest?: MemoryIngestPort;
|
|
175
190
|
}
|
|
176
191
|
export interface KtxMcpServerDeps {
|
|
@@ -179,6 +194,8 @@ export interface KtxMcpServerDeps {
|
|
|
179
194
|
contextTools?: KtxMcpContextPorts;
|
|
180
195
|
projectDir?: string;
|
|
181
196
|
io?: KtxCliIo;
|
|
197
|
+
/** Shared per-process logger for tool-call observability; tool-call logging is off when absent. */
|
|
198
|
+
logger?: KtxMcpLogger;
|
|
182
199
|
/** Reads the connected client's identity once the initialize handshake completes. */
|
|
183
200
|
getClientInfo?: () => KtxMcpClientInfo | undefined;
|
|
184
201
|
}
|
|
@@ -131,7 +131,7 @@ export class MemoryAgentService {
|
|
|
131
131
|
: '';
|
|
132
132
|
const prompt = [
|
|
133
133
|
`# Wiki Index\n\n${wikiIndex}`,
|
|
134
|
-
hasSL ? `\n# Semantic Layer Sources\n\n${slIndex}` : '',
|
|
134
|
+
hasSL ? `\n# Semantic Layer Sources (connectionId: ${input.connectionId})\n\n${slIndex}` : '',
|
|
135
135
|
'\n---\n',
|
|
136
136
|
assistantSection,
|
|
137
137
|
`\n## User Message\n\n${input.userMessage.trim()}`,
|
|
@@ -102,35 +102,51 @@ declare const scanRelationshipsSchema: z.ZodObject<{
|
|
|
102
102
|
profileConcurrency: z.ZodDefault<z.ZodInt>;
|
|
103
103
|
validationConcurrency: z.ZodDefault<z.ZodInt>;
|
|
104
104
|
validationBudget: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"all">, z.ZodInt]>>;
|
|
105
|
+
detectionBudgetMs: z.ZodDefault<z.ZodInt>;
|
|
105
106
|
}, z.core.$strict>;
|
|
106
107
|
declare const connectionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
107
108
|
driver: z.ZodLiteral<"postgres">;
|
|
108
109
|
url: z.ZodOptional<z.ZodString>;
|
|
109
110
|
enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
111
|
+
query_timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
110
112
|
}, z.core.$loose>, z.ZodObject<{
|
|
111
113
|
driver: z.ZodLiteral<"mysql">;
|
|
112
114
|
url: z.ZodOptional<z.ZodString>;
|
|
113
115
|
enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
116
|
+
query_timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
114
117
|
}, z.core.$loose>, z.ZodObject<{
|
|
115
118
|
driver: z.ZodLiteral<"snowflake">;
|
|
116
119
|
url: z.ZodOptional<z.ZodString>;
|
|
117
120
|
enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
121
|
+
query_timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
118
122
|
}, z.core.$loose>, z.ZodObject<{
|
|
119
123
|
driver: z.ZodLiteral<"bigquery">;
|
|
120
124
|
url: z.ZodOptional<z.ZodString>;
|
|
121
125
|
enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
126
|
+
query_timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
122
127
|
}, z.core.$loose>, z.ZodObject<{
|
|
123
128
|
driver: z.ZodLiteral<"sqlite">;
|
|
124
129
|
url: z.ZodOptional<z.ZodString>;
|
|
125
130
|
enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
131
|
+
query_timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
126
132
|
}, z.core.$loose>, z.ZodObject<{
|
|
127
133
|
driver: z.ZodLiteral<"clickhouse">;
|
|
128
134
|
url: z.ZodOptional<z.ZodString>;
|
|
129
135
|
enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
136
|
+
query_timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
130
137
|
}, z.core.$loose>, z.ZodObject<{
|
|
131
138
|
driver: z.ZodLiteral<"sqlserver">;
|
|
132
139
|
url: z.ZodOptional<z.ZodString>;
|
|
133
140
|
enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
141
|
+
query_timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
142
|
+
}, z.core.$loose>, z.ZodObject<{
|
|
143
|
+
driver: z.ZodLiteral<"mongodb">;
|
|
144
|
+
url: z.ZodString;
|
|
145
|
+
database: z.ZodOptional<z.ZodString>;
|
|
146
|
+
databases: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
147
|
+
enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
148
|
+
sample_size: z.ZodOptional<z.ZodNumber>;
|
|
149
|
+
order_by: z.ZodOptional<z.ZodString>;
|
|
134
150
|
}, z.core.$loose>, z.ZodObject<{
|
|
135
151
|
driver: z.ZodLiteral<"metabase">;
|
|
136
152
|
api_url: z.ZodString;
|
|
@@ -184,6 +200,11 @@ declare const connectionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
184
200
|
max_pages_per_run: z.ZodOptional<z.ZodNumber>;
|
|
185
201
|
max_knowledge_creates_per_run: z.ZodOptional<z.ZodNumber>;
|
|
186
202
|
max_knowledge_updates_per_run: z.ZodOptional<z.ZodNumber>;
|
|
203
|
+
}, z.core.$loose>, z.ZodObject<{
|
|
204
|
+
driver: z.ZodLiteral<"gdrive">;
|
|
205
|
+
service_account_key_ref: z.ZodString;
|
|
206
|
+
folder_id: z.ZodString;
|
|
207
|
+
recursive: z.ZodOptional<z.ZodBoolean>;
|
|
187
208
|
}, z.core.$loose>, z.ZodObject<{
|
|
188
209
|
driver: z.ZodLiteral<"dbt">;
|
|
189
210
|
source_dir: z.ZodOptional<z.ZodString>;
|
|
@@ -202,6 +223,21 @@ declare const connectionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
202
223
|
path: z.ZodOptional<z.ZodString>;
|
|
203
224
|
auth_token_ref: z.ZodOptional<z.ZodString>;
|
|
204
225
|
}, z.core.$loose>;
|
|
226
|
+
}, z.core.$loose>, z.ZodObject<{
|
|
227
|
+
driver: z.ZodLiteral<"sigma">;
|
|
228
|
+
api_url: z.ZodDefault<z.ZodString>;
|
|
229
|
+
client_id: z.ZodString;
|
|
230
|
+
client_secret: z.ZodOptional<z.ZodString>;
|
|
231
|
+
client_secret_ref: z.ZodOptional<z.ZodString>;
|
|
232
|
+
connectionMappings: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
233
|
+
workbookFilter: z.ZodOptional<z.ZodObject<{
|
|
234
|
+
includeArchived: z.ZodDefault<z.ZodBoolean>;
|
|
235
|
+
includeExplorations: z.ZodDefault<z.ZodBoolean>;
|
|
236
|
+
updatedSince: z.ZodOptional<z.ZodString>;
|
|
237
|
+
}, z.core.$strip>>;
|
|
238
|
+
dataModelFilter: z.ZodOptional<z.ZodObject<{
|
|
239
|
+
updatedSince: z.ZodOptional<z.ZodString>;
|
|
240
|
+
}, z.core.$strip>>;
|
|
205
241
|
}, z.core.$loose>], "driver">;
|
|
206
242
|
declare const ktxProjectConfigSchema: z.ZodObject<{
|
|
207
243
|
setup: z.ZodOptional<z.ZodObject<{
|
|
@@ -211,30 +247,45 @@ declare const ktxProjectConfigSchema: z.ZodObject<{
|
|
|
211
247
|
driver: z.ZodLiteral<"postgres">;
|
|
212
248
|
url: z.ZodOptional<z.ZodString>;
|
|
213
249
|
enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
250
|
+
query_timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
214
251
|
}, z.core.$loose>, z.ZodObject<{
|
|
215
252
|
driver: z.ZodLiteral<"mysql">;
|
|
216
253
|
url: z.ZodOptional<z.ZodString>;
|
|
217
254
|
enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
255
|
+
query_timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
218
256
|
}, z.core.$loose>, z.ZodObject<{
|
|
219
257
|
driver: z.ZodLiteral<"snowflake">;
|
|
220
258
|
url: z.ZodOptional<z.ZodString>;
|
|
221
259
|
enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
260
|
+
query_timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
222
261
|
}, z.core.$loose>, z.ZodObject<{
|
|
223
262
|
driver: z.ZodLiteral<"bigquery">;
|
|
224
263
|
url: z.ZodOptional<z.ZodString>;
|
|
225
264
|
enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
265
|
+
query_timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
226
266
|
}, z.core.$loose>, z.ZodObject<{
|
|
227
267
|
driver: z.ZodLiteral<"sqlite">;
|
|
228
268
|
url: z.ZodOptional<z.ZodString>;
|
|
229
269
|
enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
270
|
+
query_timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
230
271
|
}, z.core.$loose>, z.ZodObject<{
|
|
231
272
|
driver: z.ZodLiteral<"clickhouse">;
|
|
232
273
|
url: z.ZodOptional<z.ZodString>;
|
|
233
274
|
enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
275
|
+
query_timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
234
276
|
}, z.core.$loose>, z.ZodObject<{
|
|
235
277
|
driver: z.ZodLiteral<"sqlserver">;
|
|
236
278
|
url: z.ZodOptional<z.ZodString>;
|
|
237
279
|
enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
280
|
+
query_timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
281
|
+
}, z.core.$loose>, z.ZodObject<{
|
|
282
|
+
driver: z.ZodLiteral<"mongodb">;
|
|
283
|
+
url: z.ZodString;
|
|
284
|
+
database: z.ZodOptional<z.ZodString>;
|
|
285
|
+
databases: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
286
|
+
enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
287
|
+
sample_size: z.ZodOptional<z.ZodNumber>;
|
|
288
|
+
order_by: z.ZodOptional<z.ZodString>;
|
|
238
289
|
}, z.core.$loose>, z.ZodObject<{
|
|
239
290
|
driver: z.ZodLiteral<"metabase">;
|
|
240
291
|
api_url: z.ZodString;
|
|
@@ -288,6 +339,11 @@ declare const ktxProjectConfigSchema: z.ZodObject<{
|
|
|
288
339
|
max_pages_per_run: z.ZodOptional<z.ZodNumber>;
|
|
289
340
|
max_knowledge_creates_per_run: z.ZodOptional<z.ZodNumber>;
|
|
290
341
|
max_knowledge_updates_per_run: z.ZodOptional<z.ZodNumber>;
|
|
342
|
+
}, z.core.$loose>, z.ZodObject<{
|
|
343
|
+
driver: z.ZodLiteral<"gdrive">;
|
|
344
|
+
service_account_key_ref: z.ZodString;
|
|
345
|
+
folder_id: z.ZodString;
|
|
346
|
+
recursive: z.ZodOptional<z.ZodBoolean>;
|
|
291
347
|
}, z.core.$loose>, z.ZodObject<{
|
|
292
348
|
driver: z.ZodLiteral<"dbt">;
|
|
293
349
|
source_dir: z.ZodOptional<z.ZodString>;
|
|
@@ -306,6 +362,21 @@ declare const ktxProjectConfigSchema: z.ZodObject<{
|
|
|
306
362
|
path: z.ZodOptional<z.ZodString>;
|
|
307
363
|
auth_token_ref: z.ZodOptional<z.ZodString>;
|
|
308
364
|
}, z.core.$loose>;
|
|
365
|
+
}, z.core.$loose>, z.ZodObject<{
|
|
366
|
+
driver: z.ZodLiteral<"sigma">;
|
|
367
|
+
api_url: z.ZodDefault<z.ZodString>;
|
|
368
|
+
client_id: z.ZodString;
|
|
369
|
+
client_secret: z.ZodOptional<z.ZodString>;
|
|
370
|
+
client_secret_ref: z.ZodOptional<z.ZodString>;
|
|
371
|
+
connectionMappings: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
372
|
+
workbookFilter: z.ZodOptional<z.ZodObject<{
|
|
373
|
+
includeArchived: z.ZodDefault<z.ZodBoolean>;
|
|
374
|
+
includeExplorations: z.ZodDefault<z.ZodBoolean>;
|
|
375
|
+
updatedSince: z.ZodOptional<z.ZodString>;
|
|
376
|
+
}, z.core.$strip>>;
|
|
377
|
+
dataModelFilter: z.ZodOptional<z.ZodObject<{
|
|
378
|
+
updatedSince: z.ZodOptional<z.ZodString>;
|
|
379
|
+
}, z.core.$strip>>;
|
|
309
380
|
}, z.core.$loose>], "driver">>>;
|
|
310
381
|
storage: z.ZodPrefault<z.ZodObject<{
|
|
311
382
|
state: z.ZodDefault<z.ZodEnum<{
|
|
@@ -455,6 +526,7 @@ declare const ktxProjectConfigSchema: z.ZodObject<{
|
|
|
455
526
|
profileConcurrency: z.ZodDefault<z.ZodInt>;
|
|
456
527
|
validationConcurrency: z.ZodDefault<z.ZodInt>;
|
|
457
528
|
validationBudget: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"all">, z.ZodInt]>>;
|
|
529
|
+
detectionBudgetMs: z.ZodDefault<z.ZodInt>;
|
|
458
530
|
}, z.core.$strict>>;
|
|
459
531
|
}, z.core.$strict>>;
|
|
460
532
|
}, z.core.$strict>;
|
|
@@ -187,6 +187,11 @@ const scanRelationshipsSchema = z
|
|
|
187
187
|
.union([z.literal('all'), z.int().nonnegative()])
|
|
188
188
|
.optional()
|
|
189
189
|
.describe('Cap on validation queries per scan run. Use "all" for unlimited, an integer for a hard cap, or omit for the runtime default.'),
|
|
190
|
+
detectionBudgetMs: z
|
|
191
|
+
.int()
|
|
192
|
+
.positive()
|
|
193
|
+
.default(600_000)
|
|
194
|
+
.describe('Wall-clock budget (ms) for the whole relationship-detection stage. Checked at table-profile, LLM-proposal, candidate-validation, and composite-probe boundaries; above the per-query deadline. On exhaustion the stage stops scheduling new work and returns the relationships found so far, marked partial. Raise it to trigger a fresher, fuller run.'),
|
|
190
195
|
})
|
|
191
196
|
.describe('Schema-scan relationship discovery and validation tunables.');
|
|
192
197
|
const scanSchema = z
|
|
@@ -3,30 +3,45 @@ export declare const connectionConfigSchema: z.ZodDiscriminatedUnion<[z.ZodObjec
|
|
|
3
3
|
driver: z.ZodLiteral<"postgres">;
|
|
4
4
|
url: z.ZodOptional<z.ZodString>;
|
|
5
5
|
enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
6
|
+
query_timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
6
7
|
}, z.core.$loose>, z.ZodObject<{
|
|
7
8
|
driver: z.ZodLiteral<"mysql">;
|
|
8
9
|
url: z.ZodOptional<z.ZodString>;
|
|
9
10
|
enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
11
|
+
query_timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
10
12
|
}, z.core.$loose>, z.ZodObject<{
|
|
11
13
|
driver: z.ZodLiteral<"snowflake">;
|
|
12
14
|
url: z.ZodOptional<z.ZodString>;
|
|
13
15
|
enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
16
|
+
query_timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
14
17
|
}, z.core.$loose>, z.ZodObject<{
|
|
15
18
|
driver: z.ZodLiteral<"bigquery">;
|
|
16
19
|
url: z.ZodOptional<z.ZodString>;
|
|
17
20
|
enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
21
|
+
query_timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
18
22
|
}, z.core.$loose>, z.ZodObject<{
|
|
19
23
|
driver: z.ZodLiteral<"sqlite">;
|
|
20
24
|
url: z.ZodOptional<z.ZodString>;
|
|
21
25
|
enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
26
|
+
query_timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
22
27
|
}, z.core.$loose>, z.ZodObject<{
|
|
23
28
|
driver: z.ZodLiteral<"clickhouse">;
|
|
24
29
|
url: z.ZodOptional<z.ZodString>;
|
|
25
30
|
enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
31
|
+
query_timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
26
32
|
}, z.core.$loose>, z.ZodObject<{
|
|
27
33
|
driver: z.ZodLiteral<"sqlserver">;
|
|
28
34
|
url: z.ZodOptional<z.ZodString>;
|
|
29
35
|
enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
36
|
+
query_timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
37
|
+
}, z.core.$loose>, z.ZodObject<{
|
|
38
|
+
driver: z.ZodLiteral<"mongodb">;
|
|
39
|
+
url: z.ZodString;
|
|
40
|
+
database: z.ZodOptional<z.ZodString>;
|
|
41
|
+
databases: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
42
|
+
enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
43
|
+
sample_size: z.ZodOptional<z.ZodNumber>;
|
|
44
|
+
order_by: z.ZodOptional<z.ZodString>;
|
|
30
45
|
}, z.core.$loose>, z.ZodObject<{
|
|
31
46
|
driver: z.ZodLiteral<"metabase">;
|
|
32
47
|
api_url: z.ZodString;
|
|
@@ -80,6 +95,11 @@ export declare const connectionConfigSchema: z.ZodDiscriminatedUnion<[z.ZodObjec
|
|
|
80
95
|
max_pages_per_run: z.ZodOptional<z.ZodNumber>;
|
|
81
96
|
max_knowledge_creates_per_run: z.ZodOptional<z.ZodNumber>;
|
|
82
97
|
max_knowledge_updates_per_run: z.ZodOptional<z.ZodNumber>;
|
|
98
|
+
}, z.core.$loose>, z.ZodObject<{
|
|
99
|
+
driver: z.ZodLiteral<"gdrive">;
|
|
100
|
+
service_account_key_ref: z.ZodString;
|
|
101
|
+
folder_id: z.ZodString;
|
|
102
|
+
recursive: z.ZodOptional<z.ZodBoolean>;
|
|
83
103
|
}, z.core.$loose>, z.ZodObject<{
|
|
84
104
|
driver: z.ZodLiteral<"dbt">;
|
|
85
105
|
source_dir: z.ZodOptional<z.ZodString>;
|
|
@@ -98,4 +118,19 @@ export declare const connectionConfigSchema: z.ZodDiscriminatedUnion<[z.ZodObjec
|
|
|
98
118
|
path: z.ZodOptional<z.ZodString>;
|
|
99
119
|
auth_token_ref: z.ZodOptional<z.ZodString>;
|
|
100
120
|
}, z.core.$loose>;
|
|
121
|
+
}, z.core.$loose>, z.ZodObject<{
|
|
122
|
+
driver: z.ZodLiteral<"sigma">;
|
|
123
|
+
api_url: z.ZodDefault<z.ZodString>;
|
|
124
|
+
client_id: z.ZodString;
|
|
125
|
+
client_secret: z.ZodOptional<z.ZodString>;
|
|
126
|
+
client_secret_ref: z.ZodOptional<z.ZodString>;
|
|
127
|
+
connectionMappings: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
128
|
+
workbookFilter: z.ZodOptional<z.ZodObject<{
|
|
129
|
+
includeArchived: z.ZodDefault<z.ZodBoolean>;
|
|
130
|
+
includeExplorations: z.ZodDefault<z.ZodBoolean>;
|
|
131
|
+
updatedSince: z.ZodOptional<z.ZodString>;
|
|
132
|
+
}, z.core.$strip>>;
|
|
133
|
+
dataModelFilter: z.ZodOptional<z.ZodObject<{
|
|
134
|
+
updatedSince: z.ZodOptional<z.ZodString>;
|
|
135
|
+
}, z.core.$strip>>;
|
|
101
136
|
}, z.core.$loose>], "driver">;
|
|
@@ -21,7 +21,13 @@ function warehouseConnectionSchema(driver) {
|
|
|
21
21
|
enabled_tables: z
|
|
22
22
|
.array(z.string().min(1))
|
|
23
23
|
.optional()
|
|
24
|
-
.describe('Optional allowlist of
|
|
24
|
+
.describe('Optional allowlist of object names to ingest. Accepted forms: "catalog.db.name", "db.name" (schema-qualified), or bare "name". When set, live-database ingest restricts the scan to the listed objects and fails with a clear error if none match. For SQLite, "main.<name>" and the bare "<name>" are equivalent (SQLite exposes a single "main" schema). Useful for smoke-testing ingest on a single table.'),
|
|
25
|
+
query_timeout_ms: z
|
|
26
|
+
.number()
|
|
27
|
+
.int()
|
|
28
|
+
.positive()
|
|
29
|
+
.optional()
|
|
30
|
+
.describe('Maximum execution time for a single read-only query, in milliseconds (default 30000). Enforced as a server-side statement timeout for remote engines and by SIGKILL-ing a forked query subprocess for in-process SQLite. A query exceeding it is cancelled and returns a "query exceeded Ns" error so the agent can revise.'),
|
|
25
31
|
})
|
|
26
32
|
.describe(`${driver} warehouse connection. Additional driver-tunable fields (e.g. context.queryHistory) are accepted and passed through.`);
|
|
27
33
|
}
|
|
@@ -34,6 +40,36 @@ const warehouseConnectionSchemas = [
|
|
|
34
40
|
warehouseConnectionSchema('clickhouse'),
|
|
35
41
|
warehouseConnectionSchema('sqlserver'),
|
|
36
42
|
];
|
|
43
|
+
const mongodbConnectionSchema = z
|
|
44
|
+
.looseObject({
|
|
45
|
+
driver: z.literal('mongodb'),
|
|
46
|
+
url: z
|
|
47
|
+
.string()
|
|
48
|
+
.min(1)
|
|
49
|
+
.describe('MongoDB connection string (mongodb:// or mongodb+srv://, including TLS/Atlas); may contain a reference like env:MONGO_URL.'),
|
|
50
|
+
database: z.string().min(1).optional().describe('Single database to introspect when not using databases or a URL path.'),
|
|
51
|
+
databases: z
|
|
52
|
+
.array(z.string().min(1))
|
|
53
|
+
.optional()
|
|
54
|
+
.describe('Databases whose collections ktx introspects as tables. Falls back to the URL path database.'),
|
|
55
|
+
enabled_tables: z
|
|
56
|
+
.array(z.string().min(1))
|
|
57
|
+
.optional()
|
|
58
|
+
.describe('Optional allowlist of "database.collection" names to introspect.'),
|
|
59
|
+
sample_size: z
|
|
60
|
+
.number()
|
|
61
|
+
.int()
|
|
62
|
+
.min(1)
|
|
63
|
+
.optional()
|
|
64
|
+
.describe('How many recent documents to sample per collection when inferring the schema (default 1000).'),
|
|
65
|
+
order_by: z
|
|
66
|
+
.string()
|
|
67
|
+
.min(1)
|
|
68
|
+
.optional()
|
|
69
|
+
.describe('Field to sort by descending when sampling. Defaults to _id; set this when _id is not an ObjectId. ' +
|
|
70
|
+
'Should be indexed — an unindexed sort hits MongoDB\'s in-memory sort limit on large collections.'),
|
|
71
|
+
})
|
|
72
|
+
.describe('MongoDB primary-source connection. Schema is inferred by sampling the most recent documents.');
|
|
37
73
|
const positiveIntKeyMessage = (field) => `${field} keys must be positive-integer strings (e.g. "1", "42")`;
|
|
38
74
|
const positiveIntKeyRegex = /^[1-9]\d*$/;
|
|
39
75
|
const metabaseMappingsStrictSchema = metabaseMappingsSchema.superRefine((value, ctx) => {
|
|
@@ -145,6 +181,17 @@ const notionConnectionSchema = z
|
|
|
145
181
|
.describe('Maximum existing wiki pages updated per run.'),
|
|
146
182
|
})
|
|
147
183
|
.describe('Notion context-source connection.');
|
|
184
|
+
const gdriveConnectionSchema = z
|
|
185
|
+
.looseObject({
|
|
186
|
+
driver: z.literal('gdrive'),
|
|
187
|
+
service_account_key_ref: z
|
|
188
|
+
.string()
|
|
189
|
+
.min(1)
|
|
190
|
+
.describe('Reference to a Google service-account JSON key file. Must use file:/absolute/path/to/key.json.'),
|
|
191
|
+
folder_id: z.string().min(1).describe('Google Drive folder ID to ingest.'),
|
|
192
|
+
recursive: z.boolean().optional().describe('When true, recursively traverse subfolders beneath folder_id.'),
|
|
193
|
+
})
|
|
194
|
+
.describe('Google Drive Google Docs context-source connection.');
|
|
148
195
|
const dbtConnectionSchema = z
|
|
149
196
|
.looseObject({
|
|
150
197
|
driver: z.literal('dbt'),
|
|
@@ -171,12 +218,53 @@ const metricflowConnectionSchema = z
|
|
|
171
218
|
.describe('Nested MetricFlow configuration block.'),
|
|
172
219
|
})
|
|
173
220
|
.describe('MetricFlow / SL context-source connection.');
|
|
221
|
+
const sigmaConnectionSchema = z
|
|
222
|
+
.looseObject({
|
|
223
|
+
driver: z.literal('sigma'),
|
|
224
|
+
api_url: z
|
|
225
|
+
.string()
|
|
226
|
+
.url()
|
|
227
|
+
.default('https://api.sigmacomputing.com')
|
|
228
|
+
.describe('Sigma API base URL. Defaults to the GCP US endpoint; change for other regions.'),
|
|
229
|
+
client_id: z.string().min(1).describe('Sigma API client ID.'),
|
|
230
|
+
client_secret: z.string().min(1).optional().describe('Literal Sigma client secret. Prefer client_secret_ref.'),
|
|
231
|
+
client_secret_ref: z
|
|
232
|
+
.string()
|
|
233
|
+
.min(1)
|
|
234
|
+
.optional()
|
|
235
|
+
.describe('Reference to Sigma client secret (e.g. env:SIGMA_CLIENT_SECRET).'),
|
|
236
|
+
connectionMappings: z
|
|
237
|
+
.record(z.string(), z.string())
|
|
238
|
+
.optional()
|
|
239
|
+
.describe('Maps Sigma internal connection UUIDs to ktx warehouse connection IDs. ' +
|
|
240
|
+
'When set, projected semantic-layer sources land under the mapped warehouse connection ' +
|
|
241
|
+
'instead of the Sigma connection, enabling sl_validate. ' +
|
|
242
|
+
'Find UUIDs in data model specs under source.connectionId.'),
|
|
243
|
+
workbookFilter: z
|
|
244
|
+
.object({
|
|
245
|
+
includeArchived: z.boolean().default(false),
|
|
246
|
+
includeExplorations: z.boolean().default(false),
|
|
247
|
+
updatedSince: z.string().optional().describe('ISO 8601 date string. Only workbooks updated on or after this date are ingested.'),
|
|
248
|
+
})
|
|
249
|
+
.optional()
|
|
250
|
+
.describe('Filters applied when listing workbooks during ingest. Defaults exclude archived and exploration workbooks.'),
|
|
251
|
+
dataModelFilter: z
|
|
252
|
+
.object({
|
|
253
|
+
updatedSince: z.string().optional().describe('ISO 8601 date string. Only data models updated on or after this date are fetched.'),
|
|
254
|
+
})
|
|
255
|
+
.optional()
|
|
256
|
+
.describe('Filters applied when listing data models during ingest.'),
|
|
257
|
+
})
|
|
258
|
+
.describe('Sigma Computing API connection for ingesting data models.');
|
|
174
259
|
export const connectionConfigSchema = z.discriminatedUnion('driver', [
|
|
175
260
|
...warehouseConnectionSchemas,
|
|
261
|
+
mongodbConnectionSchema,
|
|
176
262
|
metabaseConnectionSchema,
|
|
177
263
|
lookerConnectionSchema,
|
|
178
264
|
lookmlConnectionSchema,
|
|
179
265
|
notionConnectionSchema,
|
|
266
|
+
gdriveConnectionSchema,
|
|
180
267
|
dbtConnectionSchema,
|
|
181
268
|
metricflowConnectionSchema,
|
|
269
|
+
sigmaConnectionSchema,
|
|
182
270
|
]);
|
|
@@ -7,7 +7,7 @@ import { LocalGitFileStore } from './local-git-file-store.js';
|
|
|
7
7
|
const TRACKED_SCAFFOLD_FILES = [
|
|
8
8
|
{
|
|
9
9
|
path: '.ktx/.gitignore',
|
|
10
|
-
content: 'cache/\ndb.sqlite\ndb.sqlite-*\ningest-transcripts/\nsecrets/\nsetup/\nagents/\n',
|
|
10
|
+
content: 'cache/\ndb.sqlite\ndb.sqlite-*\ningest-transcripts/\nlogs/\nsecrets/\nsetup/\nagents/\n',
|
|
11
11
|
},
|
|
12
12
|
{ path: '.ktx/prompts/.gitkeep', content: '' },
|
|
13
13
|
{ path: '.ktx/skills/.gitkeep', content: '' },
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ChildProcess } from 'node:child_process';
|
|
1
2
|
import type { KtxLlmRuntimePort } from '../../context/llm/runtime-port.js';
|
|
2
3
|
import type { KtxColumnSampleInput, KtxColumnSampleResult, KtxScanContext, KtxScanLoggerPort, KtxScanWarning, KtxTableRef, KtxTableSampleInput, KtxTableSampleResult } from './types.js';
|
|
3
4
|
interface KtxDescriptionTableColumn {
|
|
@@ -113,6 +114,8 @@ export interface KtxDescriptionGeneratorOptions {
|
|
|
113
114
|
logger?: KtxScanLoggerPort;
|
|
114
115
|
onWarning?: (warning: KtxScanWarning) => void;
|
|
115
116
|
settings: KtxDescriptionGenerationSettings;
|
|
117
|
+
/** @internal Test seam: spawn the kill-boundary child for subprocess backends. */
|
|
118
|
+
spawnSubprocessGenerateChild?: () => ChildProcess;
|
|
116
119
|
}
|
|
117
120
|
export interface KtxDescriptionPrompt {
|
|
118
121
|
system: string;
|
|
@@ -136,6 +139,7 @@ export declare class KtxDescriptionGenerator {
|
|
|
136
139
|
private readonly logger?;
|
|
137
140
|
private readonly onWarning?;
|
|
138
141
|
private readonly settings;
|
|
142
|
+
private readonly spawnSubprocessGenerateChild?;
|
|
139
143
|
constructor(options: KtxDescriptionGeneratorOptions);
|
|
140
144
|
generateColumnDescriptions(input: KtxGenerateColumnDescriptionsInput): Promise<KtxColumnAnalysisResult>;
|
|
141
145
|
generateTableDescription(input: KtxGenerateTableDescriptionInput): Promise<string | null>;
|