nl2sql-engine 0.1.0__tar.gz → 0.1.1__tar.gz
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.
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/PKG-INFO +1 -1
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/pyproject.toml +1 -1
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/api/datasource_api.py +2 -2
- nl2sql_engine-0.1.1/src/nl2sql/cli/checks.py +80 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/commands/setup.py +16 -1
- nl2sql_engine-0.1.1/src/nl2sql/cli/common/prompts.py +53 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/demo/defaults.py +12 -8
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/demo/schemas.py +12 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/demo/writers/docker.py +12 -0
- nl2sql_engine-0.1.1/src/nl2sql/common/exceptions.py +24 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/configs/manager.py +4 -1
- nl2sql_engine-0.1.1/src/nl2sql/configs/secrets.py +23 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/datasources/registry.py +52 -13
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/routes.py +8 -5
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/runtime.py +6 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql_engine.egg-info/PKG-INFO +1 -1
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql_engine.egg-info/SOURCES.txt +1 -0
- nl2sql_engine-0.1.0/src/nl2sql/cli/checks.py +0 -53
- nl2sql_engine-0.1.0/src/nl2sql/common/exceptions.py +0 -3
- nl2sql_engine-0.1.0/src/nl2sql/configs/secrets.py +0 -11
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/README.md +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/setup.cfg +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/adapters/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/adapters/duckdb/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/adapters/duckdb/adapter.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/adapters/mssql/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/adapters/mssql/adapter.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/adapters/mysql/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/adapters/mysql/adapter.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/adapters/postgres/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/adapters/postgres/adapter.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/adapters/sqlalchemy_base/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/adapters/sqlalchemy_base/adapter.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/adapters/sqlalchemy_base/models.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/adapters/sqlite/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/adapters/sqlite/adapter.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/aggregation/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/aggregation/aggregator.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/aggregation/engines/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/aggregation/engines/polars_duckdb.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/api/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/api/auth_api.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/api/benchmark_api.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/api/indexing_api.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/api/llm_api.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/api/policy_api.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/api/query_api.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/api/result_api.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/api/settings_api.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/auth/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/auth/models.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/auth/rbac.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/commands/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/commands/benchmark.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/commands/doctor.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/commands/indexing.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/commands/info.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/commands/install.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/commands/policy.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/commands/run.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/commands/visualize.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/common/decorators.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/config.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/console.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/demo/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/demo/data.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/demo/factory.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/demo/manager.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/demo/writers/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/demo/writers/sqlite.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/generators/datasources/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/generators/datasources/generator.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/generators/datasources/templates.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/generators/env/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/generators/env/generator.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/generators/env/templates.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/generators/llm/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/generators/llm/generator.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/generators/llm/templates.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/generators/policies/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/generators/policies/generator.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/generators/policies/templates.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/main.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/reporting.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/cli/types.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/common/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/common/cancellation.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/common/context.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/common/errors.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/common/event_logger.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/common/logger.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/common/metrics.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/common/resilience.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/common/settings.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/configs/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/configs/datasources.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/configs/llm.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/configs/policies.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/configs/sample_questions.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/context.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/datasources/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/datasources/discovery.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/datasources/models.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/datasources/protocols.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/evaluation/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/evaluation/benchmark_runner.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/evaluation/evaluator.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/evaluation/types.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/execution/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/execution/artifacts/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/execution/artifacts/parquet.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/execution/artifacts/store.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/execution/contracts.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/execution/execution_store.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/execution/executor/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/execution/executor/sql_executor.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/indexing/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/indexing/chunk_builder.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/indexing/embeddings.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/indexing/enrichment_service.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/indexing/models.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/indexing/orchestrator.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/indexing/vector_store.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/llm/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/llm/models.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/llm/registry.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/graph.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/graph_utils.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/aggregator/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/aggregator/node.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/aggregator/prompts.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/aggregator/schemas.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/answer_synthesizer/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/answer_synthesizer/node.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/answer_synthesizer/prompts.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/answer_synthesizer/schemas.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/ast_planner/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/ast_planner/node.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/ast_planner/prompts.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/ast_planner/schemas.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/datasource_resolver/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/datasource_resolver/node.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/datasource_resolver/schemas.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/decomposer/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/decomposer/node.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/decomposer/prompts.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/decomposer/schemas.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/executor/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/executor/node.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/generator/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/generator/node.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/generator/schemas.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/global_planner/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/global_planner/node.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/global_planner/schemas.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/refiner/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/refiner/node.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/refiner/prompts.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/refiner/schemas.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/schema_retriever/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/schema_retriever/node.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/schema_retriever/schema.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/validator/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/validator/node.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/nodes/validator/schemas.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/pipeline_runner.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/state.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/subgraphs/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/subgraphs/schemas.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/pipeline/subgraphs/sql_agent.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/public_api.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/schema/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/schema/in_memory_store.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/schema/protocol.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/schema/sqlite_store.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/schema/store.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/secrets/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/secrets/factory.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/secrets/interfaces.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/secrets/manager.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/secrets/models.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/secrets/providers/aws.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/secrets/providers/azure.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/secrets/providers/env.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/secrets/providers/hashi.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/services/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/services/callbacks/__init__.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/services/callbacks/monitor.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/services/callbacks/node_context.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/services/callbacks/node_handlers.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/services/callbacks/node_metrics.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/services/callbacks/presenter.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql/services/callbacks/token_handler.py +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql_engine.egg-info/dependency_links.txt +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql_engine.egg-info/entry_points.txt +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql_engine.egg-info/requires.txt +0 -0
- {nl2sql_engine-0.1.0 → nl2sql_engine-0.1.1}/src/nl2sql_engine.egg-info/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "nl2sql-engine"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.1" # x-release-please-version
|
|
8
8
|
description = "Natural-language-to-SQL engine, CLI and database adapters"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -10,7 +10,7 @@ import pathlib
|
|
|
10
10
|
from typing import Union, Dict, Any, List
|
|
11
11
|
|
|
12
12
|
from nl2sql.context import NL2SQLContext
|
|
13
|
-
from nl2sql.datasources.registry import DatasourceRegistry
|
|
13
|
+
from nl2sql.datasources.registry import DatasourceRegistry, mask_connection_args
|
|
14
14
|
from nl2sql.datasources.models import DatasourceConfig
|
|
15
15
|
|
|
16
16
|
|
|
@@ -123,7 +123,7 @@ class DatasourceAPI:
|
|
|
123
123
|
details = {
|
|
124
124
|
"datasource_id": adapter.datasource_id,
|
|
125
125
|
"datasource_engine_type": adapter.datasource_engine_type,
|
|
126
|
-
"connection_args": adapter.connection_args,
|
|
126
|
+
"connection_args": mask_connection_args(adapter.connection_args),
|
|
127
127
|
"statement_timeout_ms": adapter.statement_timeout_ms,
|
|
128
128
|
"row_limit": adapter.row_limit,
|
|
129
129
|
"max_bytes": adapter.max_bytes,
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import importlib.util
|
|
2
|
+
|
|
3
|
+
from rich.table import Table
|
|
4
|
+
from rich.text import Text
|
|
5
|
+
|
|
6
|
+
from nl2sql.cli.console import console
|
|
7
|
+
from nl2sql.configs import ConfigManager
|
|
8
|
+
from nl2sql.datasources import DatasourceRegistry
|
|
9
|
+
from nl2sql.secrets import SecretManager
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def check_package(name: str) -> bool:
|
|
13
|
+
"""Checks if a python package is installed."""
|
|
14
|
+
import_name = name.replace("-", "_")
|
|
15
|
+
return importlib.util.find_spec(import_name) is not None
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def verify_connectivity(print_table: bool = True) -> bool:
|
|
19
|
+
"""Checks connectivity for every configured datasource.
|
|
20
|
+
|
|
21
|
+
This backs ``nl2sql doctor``, which is what a user runs when something is
|
|
22
|
+
already wrong, so no failure mode may escape as an exception: a broken
|
|
23
|
+
config, an uninstalled driver, an unresolvable secret and a driver that
|
|
24
|
+
raises on connect all have to come back as a reported row or a message.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
bool: True only if every datasource connected. ``setup`` branches on
|
|
28
|
+
this to decide whether to warn before continuing.
|
|
29
|
+
"""
|
|
30
|
+
try:
|
|
31
|
+
config_manager = ConfigManager()
|
|
32
|
+
secret_manager = SecretManager()
|
|
33
|
+
secret_configs = config_manager.load_secrets()
|
|
34
|
+
if secret_configs:
|
|
35
|
+
secret_manager.configure(secret_configs)
|
|
36
|
+
ds_configs = config_manager.load_datasources()
|
|
37
|
+
registry = DatasourceRegistry(secret_manager)
|
|
38
|
+
except Exception as e:
|
|
39
|
+
# Externally-sourced text (paths, parser errors): print it as Text so
|
|
40
|
+
# a bracket sequence in the message cannot be parsed as rich markup.
|
|
41
|
+
console.print(Text(f"Connectivity check failed: {e}", style="red"))
|
|
42
|
+
return False
|
|
43
|
+
|
|
44
|
+
if not ds_configs:
|
|
45
|
+
console.print("[yellow]No datasources configured.[/yellow]")
|
|
46
|
+
return True
|
|
47
|
+
|
|
48
|
+
results = []
|
|
49
|
+
|
|
50
|
+
with console.status("[bold green]Verifying connectivity...[/bold green]"):
|
|
51
|
+
for config in ds_configs:
|
|
52
|
+
ds_id = getattr(config, "id", None) or "<unknown>"
|
|
53
|
+
try:
|
|
54
|
+
adapter = registry.register_datasource(config)
|
|
55
|
+
except Exception as e:
|
|
56
|
+
results.append((ds_id, False, str(e)))
|
|
57
|
+
continue
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
ok = bool(adapter.test_connection())
|
|
61
|
+
details = "" if ok else "Connection test failed."
|
|
62
|
+
except Exception as e:
|
|
63
|
+
ok, details = False, str(e)
|
|
64
|
+
results.append((ds_id, ok, details))
|
|
65
|
+
|
|
66
|
+
all_ok = all(ok for _, ok, _ in results)
|
|
67
|
+
|
|
68
|
+
if print_table:
|
|
69
|
+
conn_table = Table(show_header=True, header_style="bold cyan")
|
|
70
|
+
conn_table.add_column("Datasource ID")
|
|
71
|
+
conn_table.add_column("Status")
|
|
72
|
+
conn_table.add_column("Details")
|
|
73
|
+
|
|
74
|
+
for ds_id, ok, details in results:
|
|
75
|
+
status = "[green]OK[/green]" if ok else "[red]Failed[/red]"
|
|
76
|
+
conn_table.add_row(Text(str(ds_id)), status, Text(str(details)))
|
|
77
|
+
|
|
78
|
+
console.print(conn_table)
|
|
79
|
+
|
|
80
|
+
return all_ok
|
|
@@ -7,6 +7,7 @@ from InquirerPy import inquirer
|
|
|
7
7
|
from InquirerPy.validator import NumberValidator
|
|
8
8
|
|
|
9
9
|
from nl2sql.cli.common.decorators import handle_cli_errors
|
|
10
|
+
from nl2sql.cli.common.prompts import confirm
|
|
10
11
|
from nl2sql.cli.console import console, print_success, print_step
|
|
11
12
|
from nl2sql.cli.config import ADAPTER_DRIVERS, KNOWN_ADAPTERS
|
|
12
13
|
from nl2sql.cli.commands.install import install_package
|
|
@@ -357,8 +358,22 @@ def setup_command(demo: bool = False, lite: bool = True, docker: bool = False, a
|
|
|
357
358
|
demo_manager.setup_lite(api_key=api_key)
|
|
358
359
|
elif docker:
|
|
359
360
|
docker_dir = demo_manager.setup_docker(api_key=api_key)
|
|
360
|
-
|
|
361
|
+
# A terminal that cannot host a prompt (Git Bash/MSYS) must not be
|
|
362
|
+
# read as consent to pull images and bind ports, so the fallback is
|
|
363
|
+
# "no": the artifacts are already on disk and the panel below tells
|
|
364
|
+
# the user how to start the stack themselves.
|
|
365
|
+
if confirm(
|
|
366
|
+
"Start Docker containers now?",
|
|
367
|
+
default=True,
|
|
368
|
+
when_unavailable=False,
|
|
369
|
+
):
|
|
361
370
|
demo_manager.start_docker_containers(docker_dir)
|
|
371
|
+
else:
|
|
372
|
+
console.print(
|
|
373
|
+
f"[dim]Containers not started. To start them yourself: "
|
|
374
|
+
f"cd {escape(str(docker_dir))} && "
|
|
375
|
+
f"docker compose -f docker-compose.demo.yml up -d[/dim]"
|
|
376
|
+
)
|
|
362
377
|
|
|
363
378
|
console.print(Panel(f"""[bold yellow]Next Steps:[/bold yellow]
|
|
364
379
|
1. [bold]Verify & Index[/bold]:
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""Interactive prompts that survive a terminal which cannot host them.
|
|
2
|
+
|
|
3
|
+
Git Bash / MSYS on Windows present a TTY that is not a Windows console, so
|
|
4
|
+
``prompt_toolkit`` -- which InquirerPy builds every prompt on -- refuses to
|
|
5
|
+
attach and raises ``NoConsoleScreenBufferError``. That killed
|
|
6
|
+
``nl2sql setup --demo --docker`` with a traceback *after* it had already
|
|
7
|
+
written the demo artifacts, which is the exact flow the docs tell users to run.
|
|
8
|
+
|
|
9
|
+
The convention here: a prompt that cannot be shown is answered the way a
|
|
10
|
+
non-interactive run would answer it, and the caller states that answer
|
|
11
|
+
explicitly rather than inheriting the interactive default. The two are not the
|
|
12
|
+
same -- a prompt guarding an action with side effects defaults to "yes" when a
|
|
13
|
+
human is watching and to "no" when nobody can say otherwise.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import sys
|
|
19
|
+
|
|
20
|
+
from InquirerPy import inquirer
|
|
21
|
+
from rich.markup import escape
|
|
22
|
+
|
|
23
|
+
from nl2sql.cli.console import console
|
|
24
|
+
|
|
25
|
+
if sys.platform == "win32": # pragma: no cover - exercised only on Windows
|
|
26
|
+
from prompt_toolkit.output.win32 import NoConsoleScreenBufferError
|
|
27
|
+
else:
|
|
28
|
+
class NoConsoleScreenBufferError(Exception):
|
|
29
|
+
"""Stand-in for the Windows-only prompt_toolkit error.
|
|
30
|
+
|
|
31
|
+
``prompt_toolkit.output.win32`` asserts ``sys.platform == "win32"`` at
|
|
32
|
+
import time, so the real class cannot be imported elsewhere. This one is
|
|
33
|
+
never raised in production; it only keeps the ``except`` clause below
|
|
34
|
+
importable (and testable) on every platform.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def confirm(message: str, default: bool, when_unavailable: bool) -> bool:
|
|
39
|
+
"""Ask a yes/no question, falling back when no prompt can be displayed.
|
|
40
|
+
|
|
41
|
+
``default`` is the pre-selected answer for a human; ``when_unavailable`` is
|
|
42
|
+
the answer used when the terminal cannot host a prompt at all.
|
|
43
|
+
"""
|
|
44
|
+
try:
|
|
45
|
+
return inquirer.confirm(message=message, default=default).execute()
|
|
46
|
+
except (NoConsoleScreenBufferError, EOFError):
|
|
47
|
+
answer = "yes" if when_unavailable else "no"
|
|
48
|
+
console.print(
|
|
49
|
+
f"[yellow]No usable interactive console (Git Bash/MSYS or a "
|
|
50
|
+
f"redirected terminal). Assuming '{answer}' for:[/yellow] "
|
|
51
|
+
f"{escape(message)}"
|
|
52
|
+
)
|
|
53
|
+
return when_unavailable
|
|
@@ -69,13 +69,17 @@ DEMO_LITE_DATASOURCES = [
|
|
|
69
69
|
{"id": "manufacturing_history", "connection": {"type": "sqlite", "database": "data/demo_lite/manufacturing_history.db"}, "description": "Historical Data (Sales)"},
|
|
70
70
|
]
|
|
71
71
|
|
|
72
|
+
# Host and port are resolved from the environment so one config serves both
|
|
73
|
+
# callers: `.env.demo` defaults to localhost + the published ports for the
|
|
74
|
+
# host-side CLI, and the compose `app` service overrides them with the
|
|
75
|
+
# compose service names + internal ports.
|
|
72
76
|
DEMO_DOCKER_DATASOURCES = [
|
|
73
77
|
{
|
|
74
78
|
"id": "manufacturing_ref",
|
|
75
79
|
"connection": {
|
|
76
80
|
"type": "postgres",
|
|
77
|
-
"host": "
|
|
78
|
-
"port":
|
|
81
|
+
"host": "${env:DEMO_REF_HOST}",
|
|
82
|
+
"port": "${env:DEMO_REF_PORT}",
|
|
79
83
|
"user": "${env:DEMO_REF_USER}",
|
|
80
84
|
"password": "${env:DEMO_REF_PASSWORD}",
|
|
81
85
|
"database": "manufacturing_ref"
|
|
@@ -86,8 +90,8 @@ DEMO_DOCKER_DATASOURCES = [
|
|
|
86
90
|
"id": "manufacturing_ops",
|
|
87
91
|
"connection": {
|
|
88
92
|
"type": "postgres",
|
|
89
|
-
"host": "
|
|
90
|
-
"port":
|
|
93
|
+
"host": "${env:DEMO_OPS_HOST}",
|
|
94
|
+
"port": "${env:DEMO_OPS_PORT}",
|
|
91
95
|
"user": "${env:DEMO_OPS_USER}",
|
|
92
96
|
"password": "${env:DEMO_OPS_PASSWORD}",
|
|
93
97
|
"database": "manufacturing_ops"
|
|
@@ -98,8 +102,8 @@ DEMO_DOCKER_DATASOURCES = [
|
|
|
98
102
|
"id": "manufacturing_supply",
|
|
99
103
|
"connection": {
|
|
100
104
|
"type": "mysql",
|
|
101
|
-
"host": "
|
|
102
|
-
"port":
|
|
105
|
+
"host": "${env:DEMO_SUPPLY_HOST}",
|
|
106
|
+
"port": "${env:DEMO_SUPPLY_PORT}",
|
|
103
107
|
"user": "${env:DEMO_SUPPLY_USER}",
|
|
104
108
|
"password": "${env:DEMO_SUPPLY_PASSWORD}",
|
|
105
109
|
"database": "manufacturing_supply"
|
|
@@ -110,8 +114,8 @@ DEMO_DOCKER_DATASOURCES = [
|
|
|
110
114
|
"id": "manufacturing_history",
|
|
111
115
|
"connection": {
|
|
112
116
|
"type": "mssql",
|
|
113
|
-
"host": "
|
|
114
|
-
"port":
|
|
117
|
+
"host": "${env:DEMO_HISTORY_HOST}",
|
|
118
|
+
"port": "${env:DEMO_HISTORY_PORT}",
|
|
115
119
|
"user": "${env:DEMO_HISTORY_USER}",
|
|
116
120
|
"password": "${env:DEMO_HISTORY_PASSWORD}",
|
|
117
121
|
"database": "manufacturing_history",
|
|
@@ -323,6 +323,18 @@ services:
|
|
|
323
323
|
- "8000:8000"
|
|
324
324
|
env_file:
|
|
325
325
|
- ../.env.demo
|
|
326
|
+
environment:
|
|
327
|
+
# .env.demo points at localhost + the published ports, which is correct
|
|
328
|
+
# from the developer's machine but not from in here -- inside the compose
|
|
329
|
+
# network the databases answer on their service names and internal ports.
|
|
330
|
+
DEMO_REF_HOST: manufacturing_ref
|
|
331
|
+
DEMO_REF_PORT: 5432
|
|
332
|
+
DEMO_OPS_HOST: manufacturing_ops
|
|
333
|
+
DEMO_OPS_PORT: 5432
|
|
334
|
+
DEMO_SUPPLY_HOST: manufacturing_supply
|
|
335
|
+
DEMO_SUPPLY_PORT: 3306
|
|
336
|
+
DEMO_HISTORY_HOST: manufacturing_history
|
|
337
|
+
DEMO_HISTORY_PORT: 1433
|
|
326
338
|
volumes:
|
|
327
339
|
- ../configs:/app/configs
|
|
328
340
|
- ../data:/app/data
|
|
@@ -157,11 +157,19 @@ GO
|
|
|
157
157
|
content = f"""# NL2SQL Demo Environment Secrets
|
|
158
158
|
# Generated automatically. DO NOT COMMIT TO VERSION CONTROL.
|
|
159
159
|
|
|
160
|
+
# Host-side defaults: the published ports on localhost, for
|
|
161
|
+
# `nl2sql --env demo index` / `run` from the developer's machine. The compose
|
|
162
|
+
# `app` service overrides these with the service names and internal ports.
|
|
163
|
+
|
|
160
164
|
# 1. Manufacturing Ref (Postgres)
|
|
165
|
+
DEMO_REF_HOST=localhost
|
|
166
|
+
DEMO_REF_PORT=5433
|
|
161
167
|
DEMO_REF_USER=ref_admin
|
|
162
168
|
DEMO_REF_PASSWORD={secrets["DEMO_REF_PASSWORD"]}
|
|
163
169
|
|
|
164
170
|
# 2. Manufacturing Ops (Postgres)
|
|
171
|
+
DEMO_OPS_HOST=localhost
|
|
172
|
+
DEMO_OPS_PORT=5434
|
|
165
173
|
DEMO_OPS_USER=ops_admin
|
|
166
174
|
DEMO_OPS_PASSWORD={secrets["DEMO_OPS_PASSWORD"]}
|
|
167
175
|
|
|
@@ -170,11 +178,15 @@ DEMO_POSTGRES_USER=postgres
|
|
|
170
178
|
DEMO_POSTGRES_PASSWORD={secrets["DEMO_POSTGRES_PASSWORD"]}
|
|
171
179
|
|
|
172
180
|
# 3. Manufacturing Supply (MySQL)
|
|
181
|
+
DEMO_SUPPLY_HOST=localhost
|
|
182
|
+
DEMO_SUPPLY_PORT=3307
|
|
173
183
|
DEMO_SUPPLY_USER=supply_admin
|
|
174
184
|
DEMO_SUPPLY_PASSWORD={secrets["DEMO_SUPPLY_PASSWORD"]}
|
|
175
185
|
DEMO_MYSQL_ROOT_PASSWORD={secrets["DEMO_MYSQL_ROOT_PASSWORD"]}
|
|
176
186
|
|
|
177
187
|
# 4. Manufacturing History (MSSQL)
|
|
188
|
+
DEMO_HISTORY_HOST=localhost
|
|
189
|
+
DEMO_HISTORY_PORT=1434
|
|
178
190
|
DEMO_HISTORY_USER=history_admin
|
|
179
191
|
DEMO_HISTORY_PASSWORD={secrets["DEMO_HISTORY_PASSWORD"]}
|
|
180
192
|
DEMO_MSSQL_SA_PASSWORD={secrets["DEMO_MSSQL_SA_PASSWORD"]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from nl2sql.common.errors import PipelineError
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class NL2SQLError(Exception):
|
|
7
|
+
"""Base exception for all NL2SQL errors."""
|
|
8
|
+
pass
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class PipelineExecutionError(NL2SQLError):
|
|
12
|
+
"""Raised when a pipeline step fails where a PipelineError cannot be returned.
|
|
13
|
+
|
|
14
|
+
Most of the pipeline reports failures by putting a ``PipelineError`` into
|
|
15
|
+
graph state as a value. LangGraph conditional-edge routers cannot do that --
|
|
16
|
+
they may only return routing decisions -- so they raise this instead. The
|
|
17
|
+
structured payload is kept on ``error`` because ``error_code``, ``severity``
|
|
18
|
+
and ``is_retryable`` drive downstream handling; ``str()`` is the underlying
|
|
19
|
+
message so the CLI error decorator prints something readable.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(self, error: PipelineError):
|
|
23
|
+
super().__init__(error.message)
|
|
24
|
+
self.error = error
|
|
@@ -125,7 +125,10 @@ class ConfigManager:
|
|
|
125
125
|
|
|
126
126
|
try:
|
|
127
127
|
content = target_path.read_text(encoding="utf-8")
|
|
128
|
-
|
|
128
|
+
# An empty file parses as None. Fall back to a mapping, not a
|
|
129
|
+
# list: the envelope is a mapping, and `or []` made an empty file
|
|
130
|
+
# fail with a misleading "should be a valid dictionary".
|
|
131
|
+
raw = yaml.safe_load(content) or {}
|
|
129
132
|
|
|
130
133
|
file_config = SecretsFileConfig.model_validate(raw)
|
|
131
134
|
return file_config.providers
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
|
|
2
|
+
from typing import List
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel, Field, field_validator
|
|
5
|
+
from nl2sql.secrets.models import SecretProviderConfig
|
|
6
|
+
|
|
7
|
+
class SecretsFileConfig(BaseModel):
|
|
8
|
+
"""File-level schema for secrets.yaml."""
|
|
9
|
+
version: int = Field(1, description="Schema version")
|
|
10
|
+
providers: List[SecretProviderConfig] = Field(default_factory=list)
|
|
11
|
+
|
|
12
|
+
@field_validator("providers", mode="before")
|
|
13
|
+
@classmethod
|
|
14
|
+
def _empty_providers_means_none_configured(cls, value):
|
|
15
|
+
"""Treat ``providers:`` with nothing under it as no providers.
|
|
16
|
+
|
|
17
|
+
Secret providers are optional, so the default alone is not enough:
|
|
18
|
+
pydantic applies it only when the key is absent, and a user who
|
|
19
|
+
comments out every example leaves the key present with a null value.
|
|
20
|
+
YAML parses that as ``None``, which the annotation rejects. Coerce it
|
|
21
|
+
here so the missing key and the empty key behave the same.
|
|
22
|
+
"""
|
|
23
|
+
return [] if value is None else value
|
|
@@ -7,6 +7,32 @@ from nl2sql.datasources.protocols import DatasourceAdapterProtocol
|
|
|
7
7
|
from nl2sql.secrets import SecretManager
|
|
8
8
|
from .models import DatasourceConfig, ConnectionConfig
|
|
9
9
|
|
|
10
|
+
# Resolved connection args hold plaintext secrets (see ``resolved_connection``),
|
|
11
|
+
# so anything that renders them -- an API payload, a `doctor` row, a pydantic
|
|
12
|
+
# ValidationError repr -- has to mask them by name first.
|
|
13
|
+
SECRET_ARG_HINTS = ("password", "secret", "token", "api_key")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _is_secret_arg(key: str) -> bool:
|
|
17
|
+
return any(hint in key.lower() for hint in SECRET_ARG_HINTS)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def mask_connection_args(connection_args: Dict[str, Any]) -> Dict[str, Any]:
|
|
21
|
+
"""Returns a copy of the connection args with secret values masked."""
|
|
22
|
+
return {
|
|
23
|
+
key: ("***" if _is_secret_arg(key) and value else value)
|
|
24
|
+
for key, value in (connection_args or {}).items()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def redact_connection_secrets(text: str, connection_args: Dict[str, Any]) -> str:
|
|
29
|
+
"""Replaces every secret value from the connection args found in ``text``."""
|
|
30
|
+
for key, value in (connection_args or {}).items():
|
|
31
|
+
if _is_secret_arg(key) and isinstance(value, str) and value:
|
|
32
|
+
text = text.replace(value, "***")
|
|
33
|
+
return text
|
|
34
|
+
|
|
35
|
+
|
|
10
36
|
class DatasourceRegistry:
|
|
11
37
|
"""Manages a collection of active DatasourceAdapters.
|
|
12
38
|
|
|
@@ -38,19 +64,24 @@ class DatasourceRegistry:
|
|
|
38
64
|
def resolved_connection(self, unresolved_connection: ConnectionConfig) -> ConnectionConfig:
|
|
39
65
|
"""Resolves all secrets in a connection dictionary.
|
|
40
66
|
|
|
67
|
+
Values are returned as plain strings. ``ConnectionConfig`` declares only
|
|
68
|
+
``type`` and allows extras, so there is no type information here to tell
|
|
69
|
+
a password apart from a host, a user or a port -- wrapping every
|
|
70
|
+
placeholder in ``SecretStr`` broke every non-password field. Each
|
|
71
|
+
adapter's own config model declares which fields are secret and pydantic
|
|
72
|
+
coerces the plain string into ``SecretStr`` for those, so masking is
|
|
73
|
+
preserved exactly where it is declared.
|
|
74
|
+
|
|
41
75
|
Args:
|
|
42
76
|
unresolved_connection (ConnectionConfig): The connection dictionary with potential secrets.
|
|
43
77
|
|
|
44
78
|
Returns:
|
|
45
79
|
ConnectionConfig: The connection dictionary with resolved secrets.
|
|
46
80
|
"""
|
|
47
|
-
from pydantic import SecretStr
|
|
48
|
-
|
|
49
81
|
resolved_connection = unresolved_connection.model_dump()
|
|
50
|
-
for key, value in
|
|
82
|
+
for key, value in list(resolved_connection.items()):
|
|
51
83
|
if isinstance(value, str) and value.startswith("${") and value.endswith("}"):
|
|
52
|
-
|
|
53
|
-
resolved_connection[key] = SecretStr(secret_val)
|
|
84
|
+
resolved_connection[key] = self.find_and_resolve_secret(value)
|
|
54
85
|
return ConnectionConfig(**resolved_connection)
|
|
55
86
|
|
|
56
87
|
def register_datasources(self, configs: List[DatasourceConfig]):
|
|
@@ -95,14 +126,22 @@ class DatasourceRegistry:
|
|
|
95
126
|
if conn_type in self._available_adapters:
|
|
96
127
|
adapter_cls = self._available_adapters[conn_type]
|
|
97
128
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
129
|
+
try:
|
|
130
|
+
adapter = adapter_cls(
|
|
131
|
+
datasource_id=ds_id,
|
|
132
|
+
datasource_engine_type=conn_type,
|
|
133
|
+
connection_args=connection_args,
|
|
134
|
+
statement_timeout_ms=config.options.get("statement_timeout_ms"),
|
|
135
|
+
row_limit=config.options.get("row_limit"),
|
|
136
|
+
max_bytes=config.options.get("max_bytes"),
|
|
137
|
+
)
|
|
138
|
+
except Exception as e:
|
|
139
|
+
# A pydantic ValidationError renders the whole input dict, which
|
|
140
|
+
# now holds the plaintext password. Re-raise without the cause so
|
|
141
|
+
# neither the message nor the traceback carries it.
|
|
142
|
+
raise ValueError(
|
|
143
|
+
redact_connection_secrets(str(e), connection_args)
|
|
144
|
+
) from None
|
|
106
145
|
with self._lock:
|
|
107
146
|
self._adapters[ds_id] = adapter
|
|
108
147
|
if hasattr(adapter, "capabilities"):
|
|
@@ -4,6 +4,7 @@ from langgraph.graph import END
|
|
|
4
4
|
from langgraph.types import Send
|
|
5
5
|
|
|
6
6
|
from nl2sql.common.errors import PipelineError, ErrorSeverity, ErrorCode
|
|
7
|
+
from nl2sql.common.exceptions import PipelineExecutionError
|
|
7
8
|
from nl2sql.context import NL2SQLContext
|
|
8
9
|
from nl2sql.pipeline.graph_utils import (
|
|
9
10
|
StateAccessor,
|
|
@@ -58,11 +59,13 @@ def build_scan_layer_router(ctx: NL2SQLContext):
|
|
|
58
59
|
|
|
59
60
|
target = resolve_subgraph(datasource_id, ctx)
|
|
60
61
|
if not target:
|
|
61
|
-
raise
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
raise PipelineExecutionError(
|
|
63
|
+
PipelineError(
|
|
64
|
+
node="layer_router",
|
|
65
|
+
message=f"No compatible subgraph found for datasource '{datasource_id}'.",
|
|
66
|
+
severity=ErrorSeverity.ERROR,
|
|
67
|
+
error_code=ErrorCode.INVALID_STATE,
|
|
68
|
+
)
|
|
66
69
|
)
|
|
67
70
|
payload = build_scan_payload(state, target, node_id)
|
|
68
71
|
branches.append(Send(target, payload))
|
|
@@ -10,6 +10,7 @@ from typing import Callable, Dict, List, Optional
|
|
|
10
10
|
from nl2sql.auth import UserContext
|
|
11
11
|
from nl2sql.common.cancellation import CancellationToken
|
|
12
12
|
from nl2sql.common.errors import PipelineError, ErrorSeverity, ErrorCode
|
|
13
|
+
from nl2sql.common.exceptions import PipelineExecutionError
|
|
13
14
|
from nl2sql.common.settings import settings
|
|
14
15
|
from nl2sql.context import NL2SQLContext
|
|
15
16
|
from nl2sql.pipeline.graph import build_graph
|
|
@@ -135,6 +136,11 @@ def run_with_graph(
|
|
|
135
136
|
],
|
|
136
137
|
"final_answer": "I apologize, but the request timed out. Please try again with a simpler query.",
|
|
137
138
|
}
|
|
139
|
+
except PipelineExecutionError as e:
|
|
140
|
+
# Raised where a PipelineError cannot be returned as a value (conditional-edge
|
|
141
|
+
# routers). The payload is already structured, so surface it unchanged: the
|
|
142
|
+
# blanket catch below would relabel it UNKNOWN_ERROR and flip is_retryable.
|
|
143
|
+
return {"errors": [e.error]}
|
|
138
144
|
except Exception as e:
|
|
139
145
|
# Fallback for other runtime crashes
|
|
140
146
|
return {
|
|
@@ -52,6 +52,7 @@ src/nl2sql/cli/commands/run.py
|
|
|
52
52
|
src/nl2sql/cli/commands/setup.py
|
|
53
53
|
src/nl2sql/cli/commands/visualize.py
|
|
54
54
|
src/nl2sql/cli/common/decorators.py
|
|
55
|
+
src/nl2sql/cli/common/prompts.py
|
|
55
56
|
src/nl2sql/cli/demo/__init__.py
|
|
56
57
|
src/nl2sql/cli/demo/data.py
|
|
57
58
|
src/nl2sql/cli/demo/defaults.py
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import importlib.util
|
|
2
|
-
from typing import Dict, Tuple
|
|
3
|
-
import pathlib
|
|
4
|
-
from rich.markup import escape
|
|
5
|
-
from rich.table import Table
|
|
6
|
-
from rich.text import Text
|
|
7
|
-
from nl2sql.cli.console import console, print_success, print_error
|
|
8
|
-
|
|
9
|
-
def check_package(name: str) -> bool:
|
|
10
|
-
"""Checks if a python package is installed."""
|
|
11
|
-
import_name = name.replace("-", "_")
|
|
12
|
-
return importlib.util.find_spec(import_name) is not None
|
|
13
|
-
|
|
14
|
-
def verify_connectivity(print_table: bool = True) -> bool:
|
|
15
|
-
"""
|
|
16
|
-
Checks connectivity for all profiles in the default config.
|
|
17
|
-
Returns True if all checks passed, False otherwise.
|
|
18
|
-
"""
|
|
19
|
-
from nl2sql.common.settings import settings
|
|
20
|
-
from nl2sql.datasources import load_profiles
|
|
21
|
-
from nl2sql.diagnostics import check_connectivity as core_check
|
|
22
|
-
|
|
23
|
-
try:
|
|
24
|
-
profiles = load_profiles(pathlib.Path(settings.datasource_config_path))
|
|
25
|
-
|
|
26
|
-
with console.status("[bold green]Verifying connectivity...[/bold green]"):
|
|
27
|
-
results = core_check(list(profiles.values()))
|
|
28
|
-
|
|
29
|
-
all_ok = True
|
|
30
|
-
|
|
31
|
-
if print_table:
|
|
32
|
-
conn_table = Table(show_header=True, header_style="bold cyan")
|
|
33
|
-
conn_table.add_column("Datasource ID")
|
|
34
|
-
conn_table.add_column("Status")
|
|
35
|
-
conn_table.add_column("Details")
|
|
36
|
-
|
|
37
|
-
for ds_id, (success, msg) in results.items():
|
|
38
|
-
if not success:
|
|
39
|
-
all_ok = False
|
|
40
|
-
|
|
41
|
-
if print_table:
|
|
42
|
-
status = "[green]OK[/green]" if success else "[red]Failed[/red]"
|
|
43
|
-
details = msg if not success else ""
|
|
44
|
-
conn_table.add_row(Text(str(ds_id)), status, Text(str(details)))
|
|
45
|
-
|
|
46
|
-
if print_table:
|
|
47
|
-
console.print(conn_table)
|
|
48
|
-
|
|
49
|
-
return all_ok
|
|
50
|
-
|
|
51
|
-
except Exception as e:
|
|
52
|
-
console.print(f"[red]Connectivity check failed: {escape(str(e))}[/red]")
|
|
53
|
-
return False
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
from typing import List
|
|
3
|
-
|
|
4
|
-
from pydantic import BaseModel, Field
|
|
5
|
-
from nl2sql.secrets.models import SecretProviderConfig
|
|
6
|
-
|
|
7
|
-
class SecretsFileConfig(BaseModel):
|
|
8
|
-
"""File-level schema for secrets.yaml."""
|
|
9
|
-
version: int = Field(1, description="Schema version")
|
|
10
|
-
providers: List[SecretProviderConfig]
|
|
11
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|