precis-cli 0.1.6__tar.gz → 0.1.7__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.
- {precis_cli-0.1.6/precis_cli.egg-info → precis_cli-0.1.7}/PKG-INFO +1 -1
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/ai/providers.py +8 -3
- precis_cli-0.1.7/app/cli/shell/commands/ai/agent_interaction.py +210 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/ai/chat.py +2 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/ai/executor.py +12 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/provider.py +1 -1
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/validate.py +46 -6
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/chat_agent_runner.py +10 -7
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/chat_orchestrator.py +14 -1
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/_constraint_validator.py +62 -1
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/action_handlers.py +33 -16
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/registry.py +4 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/chat/chat_system_prompt.py +16 -7
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/config/models.py +2 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/config/presets.py +6 -4
- precis_cli-0.1.7/app/shared/services/llm/constraints/constraint_builder.py +421 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/constraints/inline_batch.py +53 -22
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/generation/config_builder.py +40 -3
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/generation/prompt_builder.py +2 -1
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/providers/__init__.py +3 -1
- precis_cli-0.1.7/app/shared/services/llm/providers/fake.py +184 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/providers/registry.py +3 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7/precis_cli.egg-info}/PKG-INFO +1 -1
- {precis_cli-0.1.6 → precis_cli-0.1.7}/precis_cli.egg-info/SOURCES.txt +2 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/pyproject.toml +1 -1
- precis_cli-0.1.6/app/shared/services/llm/constraints/constraint_builder.py +0 -177
- {precis_cli-0.1.6 → precis_cli-0.1.7}/MANIFEST.in +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/PYPI_README.md +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/README.md +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/dependencies.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/main.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/middleware/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/middleware/exception_handler.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/middleware/request_logging.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/middleware/token_auth.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/models/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/models/connection_rules.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/models/files.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/models/full_validation.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/models/project.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/models/projects.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/models/schema.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/models/v2_responses.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/models/validation.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/models/workspace.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/ai/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/ai/chat.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/ai/generate.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/ai/hardware.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/ai/jobs.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/ai/migrate.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/ai/models.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/ai/ollama.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/ai/router.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/ai/stream.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/ai/utils.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/core/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/core/connection_rules.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/core/data_sources.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/core/regex.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/core/reporting.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/files/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/files/ops.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/files/transfer.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/preview/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/preview/content_mode.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/preview/header_row.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/preview/models.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/preview/path_mode.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/preview/router.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/base.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/constraint.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/full_config.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/full_config_writer.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/helpers.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/inspection_fix.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/manifest.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/models.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/pattern.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/regex.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/scanner.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/schema.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/schema_helpers.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/settings.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/template.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/validation.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/view.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/workspaces.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/projects/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/projects/create.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/projects/open.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/projects/scan.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/validation/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/validation/common.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/validation/content_mode.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/validation/history.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/validation/inline_mode.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/validation/path_mode.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/validation/router.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/services/full_validation_response_builder.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/services/io_error_messages.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/services/preview_service.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/__main__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shared_services/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shared_services/config_ops.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shared_services/generation_ops.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shared_services/project_ops.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/ai/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/ai/delete.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/ai/diff.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/ai/display.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/ai/executor_utils.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/ai/generate.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/ai/interaction.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/ai/migrate.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/ai/resolver.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/ai/status.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/ai/switch.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/ai/utils.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/base.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/config/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/config/base.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/config/check.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/config/edit.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/config/get.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/config/init.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/config/inspect.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/config/list.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/config/set.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/config/show.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/exit.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/help.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/infer_schema.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/open.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/project.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/system.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/completer.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/config_storage.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/exceptions.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/formatter.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/interactive_menu.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/main.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/parser.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/start.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli_main.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/mcp_server.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/app_version.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/config/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/config/server.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/loader.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/loaders/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/loaders/base.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/loaders/converter.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/loaders/csv_loader.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/loaders/excel_loader.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/loaders/extractor.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/loaders/json_loader.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/loaders/registry.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/loaders/sql_loader.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/loaders/strategies/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/loaders/strategies/array_parser.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/loaders/strategies/lines_parser.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/loaders/strategies/object_parser.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/schema_info.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/specs/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/specs/base.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/specs/csv_source.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/specs/excel_source.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/specs/file_base.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/specs/json_source.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/specs/sql_source.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/encoding.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/io/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/io/yaml.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/manifest_schema/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/manifest_schema/types.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/manifest_schema/version.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/patterns/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/patterns/loader.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/patterns/writer.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/builders/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/builders/base.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/builders/composite.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/builders/conditional.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/builders/foreign_key.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/builders/registry.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/builders/scripted.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/builders/single_column.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/builders/unique.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/factory.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/reader.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/registry.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/types/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/types/constraint_file.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/types/refs.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/types.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/writer.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/loader.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/loader_parts/config_inspector.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/loader_parts/embedded_constraints.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/loader_parts/file_loaders.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/loader_parts/inspection_ids.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/loader_parts/inspector_helpers.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/loader_parts/inspector_id_checks.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/loader_parts/inspector_reference_checks.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/loader_parts/inspector_uniqueness_checks.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/loader_parts/loading_error_messages.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/loader_parts/main.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/loader_parts/path_validation.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/loader_parts/runtime.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/types.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/coverage.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/reader.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/types.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/types_parts/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/types_parts/constants.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/types_parts/data_source.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/types_parts/info.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/types_parts/manifest.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/types_parts/refs.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/types_parts/settings.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/types_parts/settings_file_processing.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/types_parts/settings_script_security.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/types_parts/settings_validation.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/types_parts/template.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/writer.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manual_data/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manual_data/types.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/regex/reader.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/regex/types.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/regex/writer.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/schema/reader.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/schema/types.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/schema/types_parts/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/schema/types_parts/column.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/schema/types_parts/column_utils.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/schema/types_parts/constraint.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/schema/types_parts/schema_id.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/schema/types_parts/source.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/schema/types_parts/source_options.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/schema/types_parts/table.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/schema/writer.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/schema_ref_check.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/template/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/template/expander.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/template/reader.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/template/types.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/transform/reader.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/transform/types.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/transform/writer.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/pydantic_messages.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/reporter/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/reporter/reporter.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/reporter/reporters/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/reporter/reporters/base.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/reporter/reporters/dingtalk_app_reporter.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/reporter/reporters/email_reporter.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/reporter/reporters/feishu_app_reporter.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/reporter/reporters/local_file_reporter.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/reporter/reporters/wecom_app_reporter.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/utils/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/utils/path_utils.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/utils/regex_extract.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/allowed_values.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/base.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/charset.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/composite.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/condition_registry.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/conditional.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/date_logic.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/foreign_key.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/key_normalization.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/not_null.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/range.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/regex.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/scripted.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/unique.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/data_engine.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/data_types.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/data_types_parts/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/data_types_parts/base.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/data_types_parts/composite.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/data_types_parts/expression.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/data_types_parts/extracted.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/data_types_parts/json_types.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/data_types_parts/scalars.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/data_types_parts/sequence.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/dataset_schema.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/eval_sandbox.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/expression_system.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/regex_flags.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/schema/builder.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/schema/models.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/aggregate.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/base.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/cast_type.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/concat.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/conditional_assign.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/date_format.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/digits.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/drop_duplicates.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/fill_na.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/filter_rows.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/lookup.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/lower_case.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/map_value.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/math_expr.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/modulo.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/regex_extract.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/registry.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/replace.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/sort_rows.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/string_split.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/strip.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/substring.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/upper_case.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/weighted_sum.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/validation_constraints.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/chat_tools/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/chat_tools/apply_actions.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/chat_tools/ask_user.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/chat_tools/read_canvas.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/chat_tools/read_project.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/chat_tools/read_table.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/chat_tools/schemas.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/chat_tools/validate_table.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/executor.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/memory.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/planner.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/tool_registry.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/tools/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/tools/config_generate.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/tools/config_refine.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/tools/config_validate.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/tools/merge_results.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/tools/plan_chunks.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/tools/script_parse.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/types.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/failure_messages.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/job_storage.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/migrate_service.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/streaming/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/streaming/event_journal.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/streaming/orchestrator.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/streaming/pending_interaction_store.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/streaming/sse_response.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/streaming/types.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/types.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/utils.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/diff/config_diff.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/hardware.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/_canvas_validator.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/_regex_validator.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/_schema_validator.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/_settings_validator.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/_transform_validator.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/action_parser.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/action_processor.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/action_validator.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/diff_compute.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/regex_handlers.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/schema_handlers.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/settings_handlers.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/specs.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/transform_handlers.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/validation_types.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/cache/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/cache/response_cache.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/chat/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/chat/response_parser.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/config/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/config/crypto.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/config/loader.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/config_generator.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/constraints/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/constraints/constraint_deletion.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/constraints/constraint_id.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/constraints/frontend_instructions.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/discovery/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/discovery/scanner.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/generation/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/generation/agent_wiring.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/generation/errors.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/generation/existing_config.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/generation/profiler.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/generation/response_parser.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/generation/service.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/models.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/providers/base.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/providers/cached_provider.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/providers/ollama.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/providers/openai.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/schema_resolver.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/suggestion_utils.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/validate_executor.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/yaml_io.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/preview/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/preview/loader.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/preview/path_validation.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/project_loader.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/schema_inference.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/schema_runtime_builder.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/chunked_loader.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/dag/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/dag/builder.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/dag/executor.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/dag/sorter.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/data_loader.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/engine.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/executor.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/extractors.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/history.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/json_payload.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/loader.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/memory_monitor.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/postprocess.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/progress.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/report_export.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/resolver.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/service.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/types.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/validators/__init__.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/validators/adapter.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/validators/base.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/validators/composite.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/validators/date_logic.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/app/start_server.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/precis_cli.egg-info/dependency_links.txt +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/precis_cli.egg-info/entry_points.txt +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/precis_cli.egg-info/requires.txt +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/precis_cli.egg-info/top_level.txt +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/setup.cfg +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/tests/test_local_file_reporter.py +0 -0
- {precis_cli-0.1.6 → precis_cli-0.1.7}/tests/test_schema_builder.py +0 -0
|
@@ -58,8 +58,10 @@ def _is_configured(p: AIProvider) -> bool:
|
|
|
58
58
|
"""判断 Provider 是否已配置。
|
|
59
59
|
|
|
60
60
|
loader.load() 已完成 env-var 覆盖,直接检查 api_key 即可。
|
|
61
|
-
本地 Provider(Ollama)不需要 API Key。
|
|
61
|
+
本地 Provider(Ollama)不需要 API Key;fake 是确定性测试 Provider,永不依赖 key。
|
|
62
62
|
"""
|
|
63
|
+
if p.type == ProviderType.FAKE:
|
|
64
|
+
return True
|
|
63
65
|
if p.deployment == DeploymentType.LOCAL:
|
|
64
66
|
return bool(p.base_url)
|
|
65
67
|
return bool(p.api_key and p.api_key.strip())
|
|
@@ -141,7 +143,7 @@ providers:
|
|
|
141
143
|
type: openai
|
|
142
144
|
base_url: https://api.deepseek.com
|
|
143
145
|
api_key: ${DEEPSEEK_API_KEY}
|
|
144
|
-
model: deepseek-
|
|
146
|
+
model: deepseek-flash
|
|
145
147
|
|
|
146
148
|
# 本地 Ollama(无需 API Key)
|
|
147
149
|
- id: ollama-local
|
|
@@ -391,7 +393,10 @@ async def create_provider(req: CreateProviderRequest) -> ProviderResponse:
|
|
|
391
393
|
try:
|
|
392
394
|
provider_type = ProviderType(req.type)
|
|
393
395
|
except ValueError:
|
|
394
|
-
raise HTTPException(
|
|
396
|
+
raise HTTPException(
|
|
397
|
+
400,
|
|
398
|
+
detail=f"不支持的 AI 服务类型「{req.type}」,目前支持 openai、ollama 两种接入方式(fake 仅用于测试演练)",
|
|
399
|
+
)
|
|
395
400
|
|
|
396
401
|
_validate_base_url(req.base_url) # SSRF 防护
|
|
397
402
|
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
#
|
|
3
|
+
# Copyright 2026 Precis Team
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
"""@fileoverview Agent 模式终端交互适配器(CLI)
|
|
17
|
+
|
|
18
|
+
为 CLI `ai chat`(默认 agent 模式)提供 apply_actions 两阶段确认与 ask_user
|
|
19
|
+
交互问答的终端实现,解开非流式环境的 fail-closed 写盘/提问闸门。
|
|
20
|
+
|
|
21
|
+
机制与 GUI 流式路径同源:回调在事件循环协程内触发(on_apply_pending /
|
|
22
|
+
on_user_input_requested),此处打印摘要后在独立 daemon 线程阻塞读终端输入,
|
|
23
|
+
经 pending interaction store 线程安全 resolve 唤醒挂起的 await_decision() /
|
|
24
|
+
await_response()。超时(5 分钟)由 controller 兜底自动 reject/skip。
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
|
+
import asyncio
|
|
30
|
+
import logging
|
|
31
|
+
import threading
|
|
32
|
+
from typing import Any
|
|
33
|
+
|
|
34
|
+
from app.cli.shell.commands.ai.executor_utils import SpinnerController
|
|
35
|
+
from app.cli.shell.formatter import Formatter
|
|
36
|
+
from app.shared.services.ai.agent.chat_tools.apply_actions import ApplyCallbacks
|
|
37
|
+
from app.shared.services.ai.agent.chat_tools.ask_user import AskCallbacks
|
|
38
|
+
|
|
39
|
+
logger = logging.getLogger(__name__)
|
|
40
|
+
|
|
41
|
+
# 终端 diff 展示上限:超长 diff 只显示前 N 行,避免刷屏(完整内容在 dry-run 文件里)
|
|
42
|
+
_MAX_DIFF_LINES = 30
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def build_agent_interaction(spinner: SpinnerController | None) -> tuple[ApplyCallbacks, AskCallbacks]:
|
|
46
|
+
"""构建 CLI 终端的 apply/ask 回调集合。
|
|
47
|
+
|
|
48
|
+
参数:
|
|
49
|
+
spinner: CLI 交互模式的 spinner 控制器(None 表示无动画,静默模式)
|
|
50
|
+
|
|
51
|
+
返回:
|
|
52
|
+
(ApplyCallbacks, AskCallbacks),注入 ChatOptions 后经 ChatAgentRunner 生效
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
def on_apply_pending(payload: dict[str, Any]) -> None:
|
|
56
|
+
# 回调在事件循环协程内同步触发,捕获运行中的 loop 供工作线程 resolve
|
|
57
|
+
loop = asyncio.get_running_loop()
|
|
58
|
+
apply_id = payload.get("apply_id", "")
|
|
59
|
+
if spinner:
|
|
60
|
+
spinner.pause()
|
|
61
|
+
_print_apply_summary(payload)
|
|
62
|
+
|
|
63
|
+
def _worker() -> None:
|
|
64
|
+
decision = _read_apply_decision()
|
|
65
|
+
try:
|
|
66
|
+
future = asyncio.run_coroutine_threadsafe(_resolve_apply(apply_id, decision), loop)
|
|
67
|
+
future.result(timeout=10)
|
|
68
|
+
except Exception:
|
|
69
|
+
logger.exception("[agent-confirm] 终端确认 resolve 失败: apply_id=%s", apply_id)
|
|
70
|
+
finally:
|
|
71
|
+
if spinner:
|
|
72
|
+
spinner.resume()
|
|
73
|
+
|
|
74
|
+
threading.Thread(target=_worker, daemon=True, name="agent-apply-confirm").start()
|
|
75
|
+
|
|
76
|
+
def on_user_input_requested(payload: dict[str, Any]) -> None:
|
|
77
|
+
loop = asyncio.get_running_loop()
|
|
78
|
+
ask_id = payload.get("ask_id", "")
|
|
79
|
+
if spinner:
|
|
80
|
+
spinner.pause()
|
|
81
|
+
_print_ask_question(payload)
|
|
82
|
+
|
|
83
|
+
def _worker() -> None:
|
|
84
|
+
response = _read_ask_response(payload)
|
|
85
|
+
try:
|
|
86
|
+
future = asyncio.run_coroutine_threadsafe(_resolve_ask(ask_id, response), loop)
|
|
87
|
+
future.result(timeout=10)
|
|
88
|
+
except Exception:
|
|
89
|
+
logger.exception("[agent-ask] 终端问答 resolve 失败: ask_id=%s", ask_id)
|
|
90
|
+
finally:
|
|
91
|
+
if spinner:
|
|
92
|
+
spinner.resume()
|
|
93
|
+
|
|
94
|
+
threading.Thread(target=_worker, daemon=True, name="agent-ask-input").start()
|
|
95
|
+
|
|
96
|
+
apply_callbacks = ApplyCallbacks(on_apply_pending=on_apply_pending)
|
|
97
|
+
ask_callbacks = AskCallbacks(on_user_input_requested=on_user_input_requested)
|
|
98
|
+
return apply_callbacks, ask_callbacks
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
async def _resolve_apply(apply_id: str, decision: str) -> None:
|
|
102
|
+
"""按 apply_id 从全局 store 取 controller 并写入决策(幂等)。"""
|
|
103
|
+
# 延迟导入与 apply_actions._run_two_phase 一致(避免 streaming 包初始化链循环导入)
|
|
104
|
+
from app.shared.services.ai.streaming.pending_interaction_store import (
|
|
105
|
+
ConfirmController,
|
|
106
|
+
get_global_pending_interaction_store,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
controller = get_global_pending_interaction_store().get(apply_id)
|
|
110
|
+
if isinstance(controller, ConfirmController):
|
|
111
|
+
await controller.resolve(decision)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
async def _resolve_ask(ask_id: str, response: dict[str, Any]) -> None:
|
|
115
|
+
from app.shared.services.ai.streaming.pending_interaction_store import (
|
|
116
|
+
InteractionController,
|
|
117
|
+
get_global_pending_interaction_store,
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
controller = get_global_pending_interaction_store().get(ask_id)
|
|
121
|
+
if isinstance(controller, InteractionController):
|
|
122
|
+
await controller.resolve(response)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _print_apply_summary(payload: dict[str, Any]) -> None:
|
|
126
|
+
"""打印写盘计划摘要:文件清单 + 状态 + 截断 diff + 汇总行。"""
|
|
127
|
+
files = payload.get("files") or []
|
|
128
|
+
print(Formatter.warning(f"\nAI 请求写入 {len(files)} 个文件:"))
|
|
129
|
+
for f in files:
|
|
130
|
+
status = f.get("status", "?")
|
|
131
|
+
path = f.get("path", "?")
|
|
132
|
+
print(f" [{status}] {path}")
|
|
133
|
+
diff = (f.get("diff") or "").strip()
|
|
134
|
+
if diff:
|
|
135
|
+
diff_lines = diff.splitlines()
|
|
136
|
+
shown = diff_lines[:_MAX_DIFF_LINES]
|
|
137
|
+
for line in shown:
|
|
138
|
+
print(f" {line}")
|
|
139
|
+
if len(diff_lines) > _MAX_DIFF_LINES:
|
|
140
|
+
print(f" ...(共 {len(diff_lines)} 行,已截断)")
|
|
141
|
+
summary = payload.get("summary")
|
|
142
|
+
if summary:
|
|
143
|
+
print(Formatter.info(f" 摘要: {summary}"))
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def _read_apply_decision() -> str:
|
|
147
|
+
"""读取 y/n 决策;空输入与非 y 输入一律 reject(写盘默认保守)。"""
|
|
148
|
+
try:
|
|
149
|
+
raw = input(Formatter.warning("确认写入以上变更?[y/N]: ")).strip().lower()
|
|
150
|
+
except EOFError:
|
|
151
|
+
return "reject"
|
|
152
|
+
return "confirm" if raw in ("y", "yes", "是") else "reject"
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def _print_ask_question(payload: dict[str, Any]) -> None:
|
|
156
|
+
print(Formatter.warning(f"\nAI 提问: {payload.get('prompt', '')}"))
|
|
157
|
+
options = payload.get("options")
|
|
158
|
+
if isinstance(options, list) and options:
|
|
159
|
+
for idx, opt in enumerate(options, start=1):
|
|
160
|
+
print(f" {idx}. {opt}")
|
|
161
|
+
if payload.get("optional"):
|
|
162
|
+
print(Formatter.info(" (直接回车跳过此问题)"))
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def _read_ask_response(payload: dict[str, Any]) -> dict[str, Any]:
|
|
166
|
+
"""按 question_type 读取终端回答,构造 AskResponseBody 形态。
|
|
167
|
+
|
|
168
|
+
形态与前端 AskUserCard 一致:{answer: str|num|bool|str[]} / {skipped: true, reason}。
|
|
169
|
+
"""
|
|
170
|
+
question_type = payload.get("question_type", "free_text")
|
|
171
|
+
optional = bool(payload.get("optional"))
|
|
172
|
+
try:
|
|
173
|
+
if question_type == "confirm":
|
|
174
|
+
raw = input("[y/N]: ").strip().lower()
|
|
175
|
+
return {"answer": raw in ("y", "yes", "是")}
|
|
176
|
+
if question_type == "choice":
|
|
177
|
+
options = payload.get("options") or []
|
|
178
|
+
raw = input(("(多选,逗号分隔) " if payload.get("multiple") else "") + "选项编号: ").strip()
|
|
179
|
+
if not raw and optional:
|
|
180
|
+
return {"skipped": True, "reason": "user_skipped"}
|
|
181
|
+
indexes = [part.strip() for part in raw.split(",") if part.strip()]
|
|
182
|
+
picked: list[str] = []
|
|
183
|
+
for part in indexes:
|
|
184
|
+
if part.isdigit() and 1 <= int(part) <= len(options):
|
|
185
|
+
picked.append(str(options[int(part) - 1]))
|
|
186
|
+
else:
|
|
187
|
+
picked.append(part)
|
|
188
|
+
if payload.get("multiple"):
|
|
189
|
+
return {"answer": picked}
|
|
190
|
+
return {"answer": picked[0] if picked else ""}
|
|
191
|
+
if question_type == "value":
|
|
192
|
+
value_type = payload.get("value_type", "string")
|
|
193
|
+
raw = input(f"输入值({value_type}): ").strip()
|
|
194
|
+
if not raw and optional:
|
|
195
|
+
return {"skipped": True, "reason": "user_skipped"}
|
|
196
|
+
if value_type in ("integer", "float"):
|
|
197
|
+
try:
|
|
198
|
+
return {"answer": float(raw) if value_type == "float" else int(raw)}
|
|
199
|
+
except ValueError:
|
|
200
|
+
return {"answer": raw}
|
|
201
|
+
if value_type == "boolean":
|
|
202
|
+
return {"answer": raw.lower() in ("y", "yes", "true", "1", "是")}
|
|
203
|
+
return {"answer": raw}
|
|
204
|
+
# free_text
|
|
205
|
+
raw = input("回答: ").strip()
|
|
206
|
+
if not raw and optional:
|
|
207
|
+
return {"skipped": True, "reason": "user_skipped"}
|
|
208
|
+
return {"answer": raw}
|
|
209
|
+
except EOFError:
|
|
210
|
+
return {"skipped": True, "reason": "eof"}
|
|
@@ -275,6 +275,8 @@ AI 助手帮助
|
|
|
275
275
|
- ForeignKey: 外键约束 (如: "关联到 orders 表的 user_id 列")
|
|
276
276
|
- Conditional: 条件约束 (如: "如果 type 等于 A 则值为 B")
|
|
277
277
|
- DateLogic: 日期逻辑约束 (如: "日期晚于 2023-01-01")
|
|
278
|
+
- Charset: 字符集约束 (如: "该列只能包含中文")
|
|
279
|
+
- Composite: 复合约束 (如: "该列必须非空且唯一")
|
|
278
280
|
"""
|
|
279
281
|
print(Formatter.info(help_text))
|
|
280
282
|
|
|
@@ -125,6 +125,15 @@ def execute_ai_chat(
|
|
|
125
125
|
context_window = resolve_context_window(provider_config)
|
|
126
126
|
max_history_tokens, _output_budget = compute_token_budgets(context_window)
|
|
127
127
|
|
|
128
|
+
# Agent 模式终端交互:注入 apply/ask 回调解开 fail-closed 写盘/提问闸门
|
|
129
|
+
# (非交互或 legacy JSON 路径不需要——legacy 走 confirm_callback 确认门)
|
|
130
|
+
agent_apply_callbacks = None
|
|
131
|
+
agent_ask_callbacks = None
|
|
132
|
+
if interactive and agent_mode:
|
|
133
|
+
from app.cli.shell.commands.ai.agent_interaction import build_agent_interaction
|
|
134
|
+
|
|
135
|
+
agent_apply_callbacks, agent_ask_callbacks = build_agent_interaction(spinner)
|
|
136
|
+
|
|
128
137
|
# 配置对话选项
|
|
129
138
|
options = ChatOptions(
|
|
130
139
|
history=history or [],
|
|
@@ -137,6 +146,9 @@ def execute_ai_chat(
|
|
|
137
146
|
agent_mode=agent_mode,
|
|
138
147
|
max_agent_iterations=5,
|
|
139
148
|
canvas_nodes=[],
|
|
149
|
+
apply_callbacks=agent_apply_callbacks,
|
|
150
|
+
ask_callbacks=agent_ask_callbacks,
|
|
151
|
+
dry_run_enabled=agent_apply_callbacks is not None,
|
|
140
152
|
)
|
|
141
153
|
|
|
142
154
|
try:
|
|
@@ -111,6 +111,39 @@ def _parse_standalone_args(args: list[str]) -> dict:
|
|
|
111
111
|
return result
|
|
112
112
|
|
|
113
113
|
|
|
114
|
+
def _extract_settings(project_config: dict | None) -> tuple[dict, dict]:
|
|
115
|
+
"""从清单 dump 中提取 (validation, script_security) 设置。
|
|
116
|
+
|
|
117
|
+
兼容两种形态:标准清单 dump(settings 嵌套在 "settings" 键下,open 命令
|
|
118
|
+
的 project_config 即此形态)与直接以 settings 内容为顶层的形态。
|
|
119
|
+
旧实现读顶层 "validation"/"script_security" 在标准形态下恒 miss。
|
|
120
|
+
"""
|
|
121
|
+
if not project_config:
|
|
122
|
+
return {}, {}
|
|
123
|
+
settings = project_config.get("settings")
|
|
124
|
+
if isinstance(settings, dict):
|
|
125
|
+
return settings.get("validation") or {}, settings.get("script_security") or {}
|
|
126
|
+
return project_config.get("validation") or {}, project_config.get("script_security") or {}
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def _load_manifest_settings(manifest_path: str) -> tuple[dict, dict]:
|
|
130
|
+
"""轻量读取清单 YAML 的 settings 段,供 standalone 模式使用。
|
|
131
|
+
|
|
132
|
+
不做完整模型加载(executor 内部自会加载并报告真正的解析错误);
|
|
133
|
+
文件不可读/非 dict 结构时静默回退默认设置。
|
|
134
|
+
"""
|
|
135
|
+
try:
|
|
136
|
+
import yaml
|
|
137
|
+
|
|
138
|
+
with open(manifest_path, encoding="utf-8") as f:
|
|
139
|
+
data = yaml.safe_load(f) or {}
|
|
140
|
+
except Exception:
|
|
141
|
+
return {}, {}
|
|
142
|
+
if not isinstance(data, dict):
|
|
143
|
+
return {}, {}
|
|
144
|
+
return _extract_settings(data)
|
|
145
|
+
|
|
146
|
+
|
|
114
147
|
def _find_dangling_option(args: list[str]) -> str | None:
|
|
115
148
|
"""检测缺值的 standalone 选项(尾部悬挂或值位置是下一个选项)。
|
|
116
149
|
|
|
@@ -236,9 +269,9 @@ class ValidateCommand(Command):
|
|
|
236
269
|
manifest_path = os.path.join(project_path, "project.precis.yaml")
|
|
237
270
|
data_dir = project_path
|
|
238
271
|
|
|
239
|
-
#
|
|
240
|
-
|
|
241
|
-
script_security = context.project_config
|
|
272
|
+
# 从项目配置中读取设置(settings 嵌套在清单 dump 的 "settings" 键下;
|
|
273
|
+
# 旧实现读顶层 "validation" 恒 miss,REPL 模式的 timeout/error_handling 实际从未生效)
|
|
274
|
+
validation_settings, script_security = _extract_settings(context.project_config)
|
|
242
275
|
|
|
243
276
|
return self._run_validation(
|
|
244
277
|
manifest_path,
|
|
@@ -255,7 +288,8 @@ class ValidateCommand(Command):
|
|
|
255
288
|
"""Standalone 模式执行校验。
|
|
256
289
|
|
|
257
290
|
直接从命令行参数获取路径,不依赖项目上下文。
|
|
258
|
-
|
|
291
|
+
读取清单内 settings(validation/script_security),缺省回退默认值
|
|
292
|
+
(timeout=30 / continue / 安全沙箱)。
|
|
259
293
|
|
|
260
294
|
Args:
|
|
261
295
|
parsed: 解析后的参数字典,包含 manifest/data_directory/table/format/report
|
|
@@ -294,8 +328,14 @@ class ValidateCommand(Command):
|
|
|
294
328
|
|
|
295
329
|
table_name = parsed["table"]
|
|
296
330
|
|
|
297
|
-
# standalone
|
|
298
|
-
|
|
331
|
+
# standalone 模式同样读取清单内的 settings(插件/CI 场景改 YAML 的
|
|
332
|
+
# timeout/error_handling 由此生效;旧实现传空 settings 导致配置被忽略,
|
|
333
|
+
# 与 SKILL.md "调整超时/错误处理" 的指引矛盾)。清单不可读时退回默认值,
|
|
334
|
+
# 真正的解析错误由 executor 加载阶段报告。
|
|
335
|
+
validation_settings, script_security = _load_manifest_settings(manifest_path)
|
|
336
|
+
return self._run_validation(
|
|
337
|
+
manifest_path, data_dir, table_name, validation_settings, script_security, output_format, parsed["report"]
|
|
338
|
+
)
|
|
299
339
|
|
|
300
340
|
def _run_validation(
|
|
301
341
|
self,
|
|
@@ -201,16 +201,19 @@ actionType 可选值({ACTION_COUNT}种):
|
|
|
201
201
|
constraintSpec.params 按类型填充对应字段:
|
|
202
202
|
|
|
203
203
|
- **NotNull**: 非空约束。参数:无。
|
|
204
|
-
- **Unique**:
|
|
204
|
+
- **Unique**: 唯一约束。单列无需参数;多列联合唯一用 constraintSpec.targetColumns(列名数组,如 ["order_id", "line_no"])。
|
|
205
205
|
- **AllowedValues**: 允许值约束。参数:`allowedValues` (List[Any])。
|
|
206
|
-
- **Range**: 范围约束。参数:`min` (float/int), `max` (float/int)。
|
|
206
|
+
- **Range**: 范围约束。参数:`min` (float/int), `max` (float/int)(至少一个),`boundaryMode` ("inclusive" 闭区间 / "exclusive" 开区间,默认 inclusive)。
|
|
207
207
|
- **Scripted**: 脚本/正则约束。二选一:`expression` (str, 代码表达式) 或 `pattern` (str, 正则)。
|
|
208
208
|
- **ForeignKey**: 外键约束。参数:`toTableId` (str), `toColumnId` (str)。
|
|
209
|
-
- **Conditional**: 条件约束。参数:`ifConditions` (List), `
|
|
210
|
-
- `ifConditions` 结构:`[{{"ifColumnId": "列名", "operator": "eq/
|
|
211
|
-
-
|
|
212
|
-
- **
|
|
213
|
-
-
|
|
209
|
+
- **Conditional**: 条件约束。参数:`ifConditions` (List), `thenCondition` (Object 或 str,必填)。
|
|
210
|
+
- `ifConditions` 结构:`[{{"ifColumnId": "列名", "operator": "eq/neq/in/not_null/greater_than/less_than", "value": "比较值", "values": 列表(in 时可选)}}]`
|
|
211
|
+
- `thenCondition` 两种形态:DSL 对象 `{{"operator": "not_null/greater_than/less_than/in/eq/neq", "value": 比较值, "values": 列表(in 时), "refColumn": "同表参考列(可选,与该列比较)"}}`;或字符串(已注册条件函数名,如 "is_not_empty")。旧字段 thenValue 已废弃,不要再使用。
|
|
212
|
+
- **DateLogic**: 日期逻辑约束。参数:`logicMode` ("compare"/"calculation")。
|
|
213
|
+
- compare 模式:`compareOp` ("gt/gte/lt/lte/eq/range"), `referenceDate` (str, "YYYY-MM-DD", 固定日期) 或 `referenceColumn` (str, 参考列,二选一);`compareOp` 为 "range" 时必须同时提供 `referenceDateEnd` 或 `referenceColumnEnd`(与起点同形态)。
|
|
214
|
+
- calculation 模式:`calculationType` ("age"/"days_diff"), `targetValue` (数值,必填);days_diff 另需 `targetColumn` (str, 天数差比较的目标列)。
|
|
215
|
+
- **Charset**: 字符集约束。参数:`charsetMode` ("ascii"/"chinese"/"chinese_mixed",必填——缺省会创建失败而非默认 ascii)。
|
|
216
|
+
- **Composite**: 复合约束(把多条子约束按逻辑聚合为一条,如"非空且唯一")。参数:`logic` ("all"/"any"/"none",默认 all), `subConstraints` (List, 必填,每项 {{"type": 约束类型, "targetColumn": "列名", "params": {{该子约束的参数}}}});不允许嵌套 Composite。
|
|
214
217
|
|
|
215
218
|
## 字段解析约定
|
|
216
219
|
|
|
@@ -26,7 +26,7 @@ import asyncio
|
|
|
26
26
|
import logging
|
|
27
27
|
from collections.abc import Callable
|
|
28
28
|
from dataclasses import dataclass, field
|
|
29
|
-
from typing import Any, Protocol
|
|
29
|
+
from typing import TYPE_CHECKING, Any, Protocol
|
|
30
30
|
|
|
31
31
|
from app.shared.services.ai.failure_messages import describe_ai_failure
|
|
32
32
|
from app.shared.services.llm.actions.action_parser import (
|
|
@@ -39,6 +39,10 @@ from app.shared.services.llm.chat.response_parser import ActionParser
|
|
|
39
39
|
from app.shared.services.llm.config.models import AIProvider
|
|
40
40
|
from app.shared.services.llm.providers.base import ChatMessage, ChatRequest
|
|
41
41
|
|
|
42
|
+
if TYPE_CHECKING:
|
|
43
|
+
from app.shared.services.ai.agent.chat_tools.apply_actions import ApplyCallbacks
|
|
44
|
+
from app.shared.services.ai.agent.chat_tools.ask_user import AskCallbacks
|
|
45
|
+
|
|
42
46
|
logger = logging.getLogger(__name__)
|
|
43
47
|
|
|
44
48
|
|
|
@@ -95,6 +99,10 @@ class ChatOptions:
|
|
|
95
99
|
max_agent_iterations: int = 5
|
|
96
100
|
# 画布节点快照(前端请求体携带,供 read_canvas 工具查询画布真实状态)
|
|
97
101
|
canvas_nodes: list[dict[str, Any]] = field(default_factory=list)
|
|
102
|
+
# Agent 模式两阶段确认/交互问答回调(CLI 终端注入;HTTP 非流式缺省 → fail-closed 保持)
|
|
103
|
+
apply_callbacks: ApplyCallbacks | None = None
|
|
104
|
+
ask_callbacks: AskCallbacks | None = None
|
|
105
|
+
dry_run_enabled: bool = False
|
|
98
106
|
|
|
99
107
|
|
|
100
108
|
@dataclass
|
|
@@ -454,6 +462,11 @@ class AIChatOrchestrator:
|
|
|
454
462
|
max_iterations=options.max_agent_iterations,
|
|
455
463
|
max_history_tokens=options.max_history_tokens,
|
|
456
464
|
canvas_nodes=options.canvas_nodes,
|
|
465
|
+
# CLI 终端环境经 ChatOptions 注入确认回调后解锁写盘/提问;
|
|
466
|
+
# HTTP 非流式缺省 None/False → apply_actions/ask_user 保持 fail-closed
|
|
467
|
+
apply_callbacks=options.apply_callbacks,
|
|
468
|
+
ask_callbacks=options.ask_callbacks,
|
|
469
|
+
dry_run_enabled=options.dry_run_enabled,
|
|
457
470
|
)
|
|
458
471
|
except Exception as e:
|
|
459
472
|
logger.error(f"Agent 模式初始化失败: {e}")
|
{precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/_constraint_validator.py
RENAMED
|
@@ -103,6 +103,31 @@ def validate_constraint_action(
|
|
|
103
103
|
|
|
104
104
|
# 2. 验证字段存在
|
|
105
105
|
column_name = spec.get("targetColumn")
|
|
106
|
+
multi_columns = spec.get("targetColumns") or spec.get("targetColumnIds") or []
|
|
107
|
+
if not column_name and isinstance(multi_columns, list) and multi_columns:
|
|
108
|
+
# 多列联合唯一:targetColumns 携带全部列引用,逐列校验存在性;
|
|
109
|
+
# 后续单列流程(类型兼容性等)以首列继续
|
|
110
|
+
for mc in multi_columns:
|
|
111
|
+
mc_name = str(mc)
|
|
112
|
+
mc_found = any(
|
|
113
|
+
col_id == mc_name or col_data["name"] == mc_name for col_id, col_data in table_info["columns"].items()
|
|
114
|
+
)
|
|
115
|
+
if not mc_found:
|
|
116
|
+
suggestion = suggest_similar_column(mc_name, table_info)
|
|
117
|
+
errors.append(
|
|
118
|
+
ValidationError(
|
|
119
|
+
action_index=index,
|
|
120
|
+
action_type=action_type,
|
|
121
|
+
error_type="column_not_found",
|
|
122
|
+
message=f"字段 '{mc_name}' 在表 '{table_info['name']}' 中不存在",
|
|
123
|
+
suggestion=suggestion,
|
|
124
|
+
auto_fixable=False,
|
|
125
|
+
)
|
|
126
|
+
)
|
|
127
|
+
if errors:
|
|
128
|
+
return errors
|
|
129
|
+
column_name = str(multi_columns[0])
|
|
130
|
+
|
|
106
131
|
if not column_name:
|
|
107
132
|
errors.append(
|
|
108
133
|
ValidationError(
|
|
@@ -260,7 +285,7 @@ def validate_constraint_params(
|
|
|
260
285
|
errors = []
|
|
261
286
|
params = spec.get("params", {})
|
|
262
287
|
|
|
263
|
-
# DateLogic
|
|
288
|
+
# DateLogic 参数完整性检查(不依赖 required_params)
|
|
264
289
|
if constraint_type == "DateLogic":
|
|
265
290
|
logic_mode = params.get("logicMode", "compare")
|
|
266
291
|
compare_op = params.get("compareOp", "gt")
|
|
@@ -279,6 +304,42 @@ def validate_constraint_params(
|
|
|
279
304
|
suggestion="请添加 params.referenceDateEnd / params.referenceColumnEnd",
|
|
280
305
|
)
|
|
281
306
|
)
|
|
307
|
+
if logic_mode == "calculation":
|
|
308
|
+
# calculation 模式(age/days_diff)参数完整性:写盘侧同样 fail-fast,此处提前拦截
|
|
309
|
+
calc = params.get("calculationType") or params.get("calculation_type")
|
|
310
|
+
if calc not in ("age", "days_diff"):
|
|
311
|
+
errors.append(
|
|
312
|
+
ValidationError(
|
|
313
|
+
action_index=index,
|
|
314
|
+
action_type=action_type,
|
|
315
|
+
error_type="missing_required_param",
|
|
316
|
+
message="DateLogic calculation 模式需要 params.calculationType(age/days_diff)",
|
|
317
|
+
suggestion="请添加 params.calculationType",
|
|
318
|
+
)
|
|
319
|
+
)
|
|
320
|
+
else:
|
|
321
|
+
target_column = params.get("targetColumn") or params.get("target_column")
|
|
322
|
+
target_value = params.get("targetValue", params.get("target_value"))
|
|
323
|
+
if calc == "days_diff" and not target_column:
|
|
324
|
+
errors.append(
|
|
325
|
+
ValidationError(
|
|
326
|
+
action_index=index,
|
|
327
|
+
action_type=action_type,
|
|
328
|
+
error_type="missing_required_param",
|
|
329
|
+
message="DateLogic days_diff 需要 params.targetColumn(天数差比较的目标列)",
|
|
330
|
+
suggestion="请添加 params.targetColumn",
|
|
331
|
+
)
|
|
332
|
+
)
|
|
333
|
+
if target_value is None:
|
|
334
|
+
errors.append(
|
|
335
|
+
ValidationError(
|
|
336
|
+
action_index=index,
|
|
337
|
+
action_type=action_type,
|
|
338
|
+
error_type="missing_required_param",
|
|
339
|
+
message="DateLogic calculation 模式需要 params.targetValue(比较目标值)",
|
|
340
|
+
suggestion="请添加 params.targetValue",
|
|
341
|
+
)
|
|
342
|
+
)
|
|
282
343
|
|
|
283
344
|
required = required_params.get(constraint_type, [])
|
|
284
345
|
if required:
|
|
@@ -53,6 +53,7 @@ from app.shared.services.llm.constraints.constraint_builder import (
|
|
|
53
53
|
CONSTRAINT_TYPE_MAP,
|
|
54
54
|
_build_constraint_params,
|
|
55
55
|
_build_constraint_refs,
|
|
56
|
+
_build_inline_constraint_item,
|
|
56
57
|
)
|
|
57
58
|
from app.shared.services.llm.constraints.constraint_deletion import delete_constraint_file
|
|
58
59
|
from app.shared.services.llm.constraints.constraint_id import _generate_constraint_id
|
|
@@ -225,18 +226,22 @@ def update_yaml_config(action: dict[str, Any], workspace_path: str) -> tuple[boo
|
|
|
225
226
|
target_node_id = constraint_spec.get("targetNodeId", "")
|
|
226
227
|
target_column_id = constraint_spec.get("targetColumnId", "")
|
|
227
228
|
is_inline = constraint_spec.get("isInline", False)
|
|
229
|
+
# 多列联合唯一:targetColumns(列名/ID 数组)可作为 targetColumn 的替代
|
|
230
|
+
target_columns = constraint_spec.get("targetColumnIds") or constraint_spec.get("targetColumns") or []
|
|
228
231
|
|
|
229
232
|
# 统一转换类型名
|
|
230
233
|
std_type = CONSTRAINT_TYPE_MAP.get(constraint_type, constraint_type)
|
|
231
234
|
|
|
232
|
-
if not std_type or not target_column:
|
|
235
|
+
if not std_type or (not target_column and not target_columns):
|
|
233
236
|
error_msg = f"无效的约束规格: constraint_type={constraint_type}, std_type={std_type}, table_name={table_name}, target_column={target_column}"
|
|
234
237
|
logger.error(f"[updateYamlConfig] {error_msg}")
|
|
235
238
|
return False, error_msg
|
|
236
239
|
|
|
237
240
|
# 确定用于文件名的表标识符 (优先使用可读的名称)
|
|
238
241
|
filename_table = table_name or target_node_id or "unknown"
|
|
239
|
-
filename_column =
|
|
242
|
+
filename_column = (
|
|
243
|
+
target_column or target_column_id or ("_".join(str(c) for c in target_columns) if target_columns else "unknown")
|
|
244
|
+
)
|
|
240
245
|
|
|
241
246
|
# DELETE 动作必须先于 is_inline 分支处理:删除语义与存储形态无关,
|
|
242
247
|
# 旧实现 isInline=true 时先命中内联"添加"分支,只增不删还误报 success。
|
|
@@ -307,26 +312,36 @@ def update_yaml_config(action: dict[str, Any], workspace_path: str) -> tuple[boo
|
|
|
307
312
|
column_id = col.get("id")
|
|
308
313
|
break
|
|
309
314
|
|
|
310
|
-
|
|
315
|
+
# 多列联合唯一:单列引用可缺省(targetColumns 携带全部列引用,由共用构建器解析)
|
|
316
|
+
is_multi_unique = std_type == "Unique" and isinstance(target_columns, list) and len(target_columns) > 1
|
|
317
|
+
if not column_id and not is_multi_unique:
|
|
311
318
|
# 目标列不存在时必须返回失败,否则会静默成功(与 process_inline_batch 对齐)。
|
|
312
319
|
error_msg = f"未找到列: {target_column}"
|
|
313
320
|
logger.warning(f"[updateYamlConfig] {error_msg}")
|
|
314
321
|
return False, error_msg
|
|
315
322
|
|
|
316
|
-
#
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
323
|
+
# 构建内联约束结构(共用构建器:Conditional 引用入 params、FK 目标入顶层字段、
|
|
324
|
+
# 多列 Unique 用 columns 列表,三种特殊形态与 process_inline_batch 收敛到同一实现)
|
|
325
|
+
inline_constraint = _build_inline_constraint_item(
|
|
326
|
+
std_type,
|
|
327
|
+
constraint_spec,
|
|
328
|
+
column_id or "",
|
|
329
|
+
columns,
|
|
330
|
+
table_name,
|
|
331
|
+
target_column,
|
|
332
|
+
workspace_path,
|
|
333
|
+
constraint_id,
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
# 检查是否已存在相同列(或列组合)和类型的约束
|
|
327
337
|
existing_idx = None
|
|
328
338
|
for idx, existing in enumerate(schema_data["constraints"]):
|
|
329
|
-
|
|
339
|
+
same_target = (
|
|
340
|
+
existing.get("columns") == inline_constraint.get("columns")
|
|
341
|
+
if "columns" in inline_constraint
|
|
342
|
+
else existing.get("column") == inline_constraint.get("column")
|
|
343
|
+
)
|
|
344
|
+
if same_target and existing.get("type") == std_type:
|
|
330
345
|
existing_idx = idx
|
|
331
346
|
break
|
|
332
347
|
|
|
@@ -377,7 +392,9 @@ def update_yaml_config(action: dict[str, Any], workspace_path: str) -> tuple[boo
|
|
|
377
392
|
enabled=True,
|
|
378
393
|
description=None,
|
|
379
394
|
refs=_build_constraint_refs(std_type, table_name, target_column, constraint_spec, workspace_path),
|
|
380
|
-
params=_build_constraint_params(
|
|
395
|
+
params=_build_constraint_params(
|
|
396
|
+
std_type, constraint_spec, table_name, target_column, workspace_path, constraint_id
|
|
397
|
+
),
|
|
381
398
|
input_from_node=None,
|
|
382
399
|
input_column=None,
|
|
383
400
|
)
|
|
@@ -79,10 +79,14 @@ ALL_CONSTRAINT_TYPES: frozenset[str] = CONSTRAINT_TYPES | frozenset(CONSTRAINT_T
|
|
|
79
79
|
# 需要特定参数的约束类型(供参数完整性校验)
|
|
80
80
|
# 注意:Range 的 min/max 实际允许"至少一个"(见 _constraint_validator 特殊处理),
|
|
81
81
|
# 此处仅声明"需要关注的参数键",具体宽松度由 validator 决定。
|
|
82
|
+
# Charset 必填 charsetMode:缺省时写盘侧不再静默默认 ascii(中文约束误判为 ascii 约束);
|
|
83
|
+
# Composite 必填 subConstraints:空子约束在引擎侧恒真(no-op 假通过)。
|
|
82
84
|
CONSTRAINT_REQUIRED_PARAMS: dict[str, list[str]] = {
|
|
83
85
|
"Range": ["min", "max"],
|
|
84
86
|
"AllowedValues": ["allowedValues"],
|
|
85
87
|
"ForeignKey": ["toTableId", "toColumnId"],
|
|
88
|
+
"Charset": ["charsetMode"],
|
|
89
|
+
"Composite": ["subConstraints"],
|
|
86
90
|
}
|
|
87
91
|
|
|
88
92
|
# 转换子类型白名单(22种)——原 response_parser(21条) 与 transform_handlers(22条) 不一致,
|