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.
Files changed (454) hide show
  1. {precis_cli-0.1.6/precis_cli.egg-info → precis_cli-0.1.7}/PKG-INFO +1 -1
  2. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/ai/providers.py +8 -3
  3. precis_cli-0.1.7/app/cli/shell/commands/ai/agent_interaction.py +210 -0
  4. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/ai/chat.py +2 -0
  5. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/ai/executor.py +12 -0
  6. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/provider.py +1 -1
  7. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/validate.py +46 -6
  8. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/chat_agent_runner.py +10 -7
  9. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/chat_orchestrator.py +14 -1
  10. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/_constraint_validator.py +62 -1
  11. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/action_handlers.py +33 -16
  12. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/registry.py +4 -0
  13. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/chat/chat_system_prompt.py +16 -7
  14. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/config/models.py +2 -0
  15. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/config/presets.py +6 -4
  16. precis_cli-0.1.7/app/shared/services/llm/constraints/constraint_builder.py +421 -0
  17. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/constraints/inline_batch.py +53 -22
  18. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/generation/config_builder.py +40 -3
  19. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/generation/prompt_builder.py +2 -1
  20. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/providers/__init__.py +3 -1
  21. precis_cli-0.1.7/app/shared/services/llm/providers/fake.py +184 -0
  22. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/providers/registry.py +3 -0
  23. {precis_cli-0.1.6 → precis_cli-0.1.7/precis_cli.egg-info}/PKG-INFO +1 -1
  24. {precis_cli-0.1.6 → precis_cli-0.1.7}/precis_cli.egg-info/SOURCES.txt +2 -0
  25. {precis_cli-0.1.6 → precis_cli-0.1.7}/pyproject.toml +1 -1
  26. precis_cli-0.1.6/app/shared/services/llm/constraints/constraint_builder.py +0 -177
  27. {precis_cli-0.1.6 → precis_cli-0.1.7}/MANIFEST.in +0 -0
  28. {precis_cli-0.1.6 → precis_cli-0.1.7}/PYPI_README.md +0 -0
  29. {precis_cli-0.1.6 → precis_cli-0.1.7}/README.md +0 -0
  30. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/__init__.py +0 -0
  31. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/__init__.py +0 -0
  32. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/dependencies.py +0 -0
  33. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/main.py +0 -0
  34. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/middleware/__init__.py +0 -0
  35. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/middleware/exception_handler.py +0 -0
  36. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/middleware/request_logging.py +0 -0
  37. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/middleware/token_auth.py +0 -0
  38. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/models/__init__.py +0 -0
  39. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/models/connection_rules.py +0 -0
  40. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/models/files.py +0 -0
  41. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/models/full_validation.py +0 -0
  42. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/models/project.py +0 -0
  43. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/models/projects.py +0 -0
  44. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/models/schema.py +0 -0
  45. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/models/v2_responses.py +0 -0
  46. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/models/validation.py +0 -0
  47. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/models/workspace.py +0 -0
  48. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/__init__.py +0 -0
  49. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/ai/__init__.py +0 -0
  50. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/ai/chat.py +0 -0
  51. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/ai/generate.py +0 -0
  52. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/ai/hardware.py +0 -0
  53. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/ai/jobs.py +0 -0
  54. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/ai/migrate.py +0 -0
  55. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/ai/models.py +0 -0
  56. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/ai/ollama.py +0 -0
  57. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/ai/router.py +0 -0
  58. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/ai/stream.py +0 -0
  59. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/ai/utils.py +0 -0
  60. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/core/__init__.py +0 -0
  61. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/core/connection_rules.py +0 -0
  62. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/core/data_sources.py +0 -0
  63. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/core/regex.py +0 -0
  64. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/core/reporting.py +0 -0
  65. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/files/__init__.py +0 -0
  66. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/files/ops.py +0 -0
  67. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/files/transfer.py +0 -0
  68. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/preview/__init__.py +0 -0
  69. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/preview/content_mode.py +0 -0
  70. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/preview/header_row.py +0 -0
  71. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/preview/models.py +0 -0
  72. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/preview/path_mode.py +0 -0
  73. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/preview/router.py +0 -0
  74. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/__init__.py +0 -0
  75. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/base.py +0 -0
  76. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/constraint.py +0 -0
  77. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/full_config.py +0 -0
  78. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/full_config_writer.py +0 -0
  79. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/helpers.py +0 -0
  80. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/inspection_fix.py +0 -0
  81. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/manifest.py +0 -0
  82. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/models.py +0 -0
  83. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/pattern.py +0 -0
  84. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/regex.py +0 -0
  85. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/scanner.py +0 -0
  86. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/schema.py +0 -0
  87. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/schema_helpers.py +0 -0
  88. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/settings.py +0 -0
  89. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/template.py +0 -0
  90. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/validation.py +0 -0
  91. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/view.py +0 -0
  92. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/project/workspaces.py +0 -0
  93. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/projects/__init__.py +0 -0
  94. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/projects/create.py +0 -0
  95. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/projects/open.py +0 -0
  96. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/projects/scan.py +0 -0
  97. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/validation/__init__.py +0 -0
  98. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/validation/common.py +0 -0
  99. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/validation/content_mode.py +0 -0
  100. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/validation/history.py +0 -0
  101. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/validation/inline_mode.py +0 -0
  102. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/validation/path_mode.py +0 -0
  103. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/routers/validation/router.py +0 -0
  104. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/services/full_validation_response_builder.py +0 -0
  105. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/services/io_error_messages.py +0 -0
  106. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/api/services/preview_service.py +0 -0
  107. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/__init__.py +0 -0
  108. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/__main__.py +0 -0
  109. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shared_services/__init__.py +0 -0
  110. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shared_services/config_ops.py +0 -0
  111. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shared_services/generation_ops.py +0 -0
  112. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shared_services/project_ops.py +0 -0
  113. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/__init__.py +0 -0
  114. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/__init__.py +0 -0
  115. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/ai/__init__.py +0 -0
  116. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/ai/delete.py +0 -0
  117. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/ai/diff.py +0 -0
  118. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/ai/display.py +0 -0
  119. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/ai/executor_utils.py +0 -0
  120. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/ai/generate.py +0 -0
  121. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/ai/interaction.py +0 -0
  122. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/ai/migrate.py +0 -0
  123. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/ai/resolver.py +0 -0
  124. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/ai/status.py +0 -0
  125. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/ai/switch.py +0 -0
  126. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/ai/utils.py +0 -0
  127. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/base.py +0 -0
  128. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/config/__init__.py +0 -0
  129. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/config/base.py +0 -0
  130. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/config/check.py +0 -0
  131. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/config/edit.py +0 -0
  132. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/config/get.py +0 -0
  133. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/config/init.py +0 -0
  134. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/config/inspect.py +0 -0
  135. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/config/list.py +0 -0
  136. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/config/set.py +0 -0
  137. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/config/show.py +0 -0
  138. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/exit.py +0 -0
  139. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/help.py +0 -0
  140. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/infer_schema.py +0 -0
  141. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/open.py +0 -0
  142. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/project.py +0 -0
  143. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/commands/system.py +0 -0
  144. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/completer.py +0 -0
  145. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/config_storage.py +0 -0
  146. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/exceptions.py +0 -0
  147. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/formatter.py +0 -0
  148. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/interactive_menu.py +0 -0
  149. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/main.py +0 -0
  150. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/shell/parser.py +0 -0
  151. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli/start.py +0 -0
  152. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/cli_main.py +0 -0
  153. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/mcp_server.py +0 -0
  154. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/__init__.py +0 -0
  155. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/app_version.py +0 -0
  156. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/config/__init__.py +0 -0
  157. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/config/server.py +0 -0
  158. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/__init__.py +0 -0
  159. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/loader.py +0 -0
  160. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/loaders/__init__.py +0 -0
  161. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/loaders/base.py +0 -0
  162. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/loaders/converter.py +0 -0
  163. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/loaders/csv_loader.py +0 -0
  164. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/loaders/excel_loader.py +0 -0
  165. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/loaders/extractor.py +0 -0
  166. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/loaders/json_loader.py +0 -0
  167. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/loaders/registry.py +0 -0
  168. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/loaders/sql_loader.py +0 -0
  169. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/loaders/strategies/__init__.py +0 -0
  170. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/loaders/strategies/array_parser.py +0 -0
  171. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/loaders/strategies/lines_parser.py +0 -0
  172. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/loaders/strategies/object_parser.py +0 -0
  173. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/schema_info.py +0 -0
  174. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/specs/__init__.py +0 -0
  175. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/specs/base.py +0 -0
  176. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/specs/csv_source.py +0 -0
  177. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/specs/excel_source.py +0 -0
  178. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/specs/file_base.py +0 -0
  179. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/specs/json_source.py +0 -0
  180. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/data_source/specs/sql_source.py +0 -0
  181. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/encoding.py +0 -0
  182. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/io/__init__.py +0 -0
  183. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/io/yaml.py +0 -0
  184. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/manifest_schema/__init__.py +0 -0
  185. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/manifest_schema/types.py +0 -0
  186. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/manifest_schema/version.py +0 -0
  187. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/patterns/__init__.py +0 -0
  188. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/patterns/loader.py +0 -0
  189. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/patterns/writer.py +0 -0
  190. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/__init__.py +0 -0
  191. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/builders/__init__.py +0 -0
  192. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/builders/base.py +0 -0
  193. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/builders/composite.py +0 -0
  194. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/builders/conditional.py +0 -0
  195. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/builders/foreign_key.py +0 -0
  196. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/builders/registry.py +0 -0
  197. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/builders/scripted.py +0 -0
  198. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/builders/single_column.py +0 -0
  199. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/builders/unique.py +0 -0
  200. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/factory.py +0 -0
  201. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/reader.py +0 -0
  202. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/registry.py +0 -0
  203. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/types/__init__.py +0 -0
  204. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/types/constraint_file.py +0 -0
  205. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/types/refs.py +0 -0
  206. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/types.py +0 -0
  207. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/constraint/writer.py +0 -0
  208. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/__init__.py +0 -0
  209. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/loader.py +0 -0
  210. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/loader_parts/config_inspector.py +0 -0
  211. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/loader_parts/embedded_constraints.py +0 -0
  212. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/loader_parts/file_loaders.py +0 -0
  213. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/loader_parts/inspection_ids.py +0 -0
  214. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/loader_parts/inspector_helpers.py +0 -0
  215. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/loader_parts/inspector_id_checks.py +0 -0
  216. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/loader_parts/inspector_reference_checks.py +0 -0
  217. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/loader_parts/inspector_uniqueness_checks.py +0 -0
  218. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/loader_parts/loading_error_messages.py +0 -0
  219. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/loader_parts/main.py +0 -0
  220. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/loader_parts/path_validation.py +0 -0
  221. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/loader_parts/runtime.py +0 -0
  222. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/loader/types.py +0 -0
  223. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/coverage.py +0 -0
  224. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/reader.py +0 -0
  225. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/types.py +0 -0
  226. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/types_parts/__init__.py +0 -0
  227. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/types_parts/constants.py +0 -0
  228. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/types_parts/data_source.py +0 -0
  229. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/types_parts/info.py +0 -0
  230. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/types_parts/manifest.py +0 -0
  231. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/types_parts/refs.py +0 -0
  232. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/types_parts/settings.py +0 -0
  233. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/types_parts/settings_file_processing.py +0 -0
  234. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/types_parts/settings_script_security.py +0 -0
  235. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/types_parts/settings_validation.py +0 -0
  236. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/types_parts/template.py +0 -0
  237. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manifest/writer.py +0 -0
  238. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manual_data/__init__.py +0 -0
  239. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/manual_data/types.py +0 -0
  240. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/regex/reader.py +0 -0
  241. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/regex/types.py +0 -0
  242. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/regex/writer.py +0 -0
  243. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/schema/reader.py +0 -0
  244. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/schema/types.py +0 -0
  245. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/schema/types_parts/__init__.py +0 -0
  246. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/schema/types_parts/column.py +0 -0
  247. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/schema/types_parts/column_utils.py +0 -0
  248. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/schema/types_parts/constraint.py +0 -0
  249. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/schema/types_parts/schema_id.py +0 -0
  250. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/schema/types_parts/source.py +0 -0
  251. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/schema/types_parts/source_options.py +0 -0
  252. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/schema/types_parts/table.py +0 -0
  253. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/schema/writer.py +0 -0
  254. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/schema_ref_check.py +0 -0
  255. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/template/__init__.py +0 -0
  256. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/template/expander.py +0 -0
  257. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/template/reader.py +0 -0
  258. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/template/types.py +0 -0
  259. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/transform/reader.py +0 -0
  260. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/transform/types.py +0 -0
  261. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/project/transform/writer.py +0 -0
  262. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/pydantic_messages.py +0 -0
  263. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/reporter/__init__.py +0 -0
  264. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/reporter/reporter.py +0 -0
  265. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/reporter/reporters/__init__.py +0 -0
  266. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/reporter/reporters/base.py +0 -0
  267. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/reporter/reporters/dingtalk_app_reporter.py +0 -0
  268. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/reporter/reporters/email_reporter.py +0 -0
  269. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/reporter/reporters/feishu_app_reporter.py +0 -0
  270. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/reporter/reporters/local_file_reporter.py +0 -0
  271. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/reporter/reporters/wecom_app_reporter.py +0 -0
  272. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/utils/__init__.py +0 -0
  273. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/utils/path_utils.py +0 -0
  274. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/core/utils/regex_extract.py +0 -0
  275. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/__init__.py +0 -0
  276. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/__init__.py +0 -0
  277. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/allowed_values.py +0 -0
  278. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/base.py +0 -0
  279. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/charset.py +0 -0
  280. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/composite.py +0 -0
  281. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/condition_registry.py +0 -0
  282. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/conditional.py +0 -0
  283. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/date_logic.py +0 -0
  284. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/foreign_key.py +0 -0
  285. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/key_normalization.py +0 -0
  286. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/not_null.py +0 -0
  287. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/range.py +0 -0
  288. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/regex.py +0 -0
  289. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/scripted.py +0 -0
  290. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/constraints/unique.py +0 -0
  291. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/data_engine.py +0 -0
  292. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/data_types.py +0 -0
  293. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/data_types_parts/__init__.py +0 -0
  294. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/data_types_parts/base.py +0 -0
  295. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/data_types_parts/composite.py +0 -0
  296. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/data_types_parts/expression.py +0 -0
  297. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/data_types_parts/extracted.py +0 -0
  298. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/data_types_parts/json_types.py +0 -0
  299. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/data_types_parts/scalars.py +0 -0
  300. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/data_types_parts/sequence.py +0 -0
  301. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/dataset_schema.py +0 -0
  302. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/eval_sandbox.py +0 -0
  303. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/expression_system.py +0 -0
  304. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/regex_flags.py +0 -0
  305. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/schema/builder.py +0 -0
  306. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/schema/models.py +0 -0
  307. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/__init__.py +0 -0
  308. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/aggregate.py +0 -0
  309. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/base.py +0 -0
  310. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/cast_type.py +0 -0
  311. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/concat.py +0 -0
  312. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/conditional_assign.py +0 -0
  313. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/date_format.py +0 -0
  314. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/digits.py +0 -0
  315. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/drop_duplicates.py +0 -0
  316. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/fill_na.py +0 -0
  317. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/filter_rows.py +0 -0
  318. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/lookup.py +0 -0
  319. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/lower_case.py +0 -0
  320. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/map_value.py +0 -0
  321. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/math_expr.py +0 -0
  322. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/modulo.py +0 -0
  323. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/regex_extract.py +0 -0
  324. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/registry.py +0 -0
  325. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/replace.py +0 -0
  326. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/sort_rows.py +0 -0
  327. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/string_split.py +0 -0
  328. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/strip.py +0 -0
  329. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/substring.py +0 -0
  330. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/upper_case.py +0 -0
  331. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/transforms/weighted_sum.py +0 -0
  332. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/domain/validation_constraints.py +0 -0
  333. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/__init__.py +0 -0
  334. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/__init__.py +0 -0
  335. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/__init__.py +0 -0
  336. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/chat_tools/__init__.py +0 -0
  337. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/chat_tools/apply_actions.py +0 -0
  338. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/chat_tools/ask_user.py +0 -0
  339. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/chat_tools/read_canvas.py +0 -0
  340. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/chat_tools/read_project.py +0 -0
  341. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/chat_tools/read_table.py +0 -0
  342. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/chat_tools/schemas.py +0 -0
  343. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/chat_tools/validate_table.py +0 -0
  344. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/executor.py +0 -0
  345. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/memory.py +0 -0
  346. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/planner.py +0 -0
  347. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/tool_registry.py +0 -0
  348. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/tools/__init__.py +0 -0
  349. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/tools/config_generate.py +0 -0
  350. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/tools/config_refine.py +0 -0
  351. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/tools/config_validate.py +0 -0
  352. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/tools/merge_results.py +0 -0
  353. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/tools/plan_chunks.py +0 -0
  354. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/tools/script_parse.py +0 -0
  355. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/agent/types.py +0 -0
  356. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/failure_messages.py +0 -0
  357. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/job_storage.py +0 -0
  358. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/migrate_service.py +0 -0
  359. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/streaming/__init__.py +0 -0
  360. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/streaming/event_journal.py +0 -0
  361. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/streaming/orchestrator.py +0 -0
  362. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/streaming/pending_interaction_store.py +0 -0
  363. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/streaming/sse_response.py +0 -0
  364. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/streaming/types.py +0 -0
  365. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/types.py +0 -0
  366. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/ai/utils.py +0 -0
  367. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/diff/config_diff.py +0 -0
  368. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/hardware.py +0 -0
  369. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/__init__.py +0 -0
  370. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/__init__.py +0 -0
  371. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/_canvas_validator.py +0 -0
  372. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/_regex_validator.py +0 -0
  373. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/_schema_validator.py +0 -0
  374. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/_settings_validator.py +0 -0
  375. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/_transform_validator.py +0 -0
  376. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/action_parser.py +0 -0
  377. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/action_processor.py +0 -0
  378. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/action_validator.py +0 -0
  379. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/diff_compute.py +0 -0
  380. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/regex_handlers.py +0 -0
  381. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/schema_handlers.py +0 -0
  382. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/settings_handlers.py +0 -0
  383. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/specs.py +0 -0
  384. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/transform_handlers.py +0 -0
  385. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/actions/validation_types.py +0 -0
  386. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/cache/__init__.py +0 -0
  387. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/cache/response_cache.py +0 -0
  388. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/chat/__init__.py +0 -0
  389. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/chat/response_parser.py +0 -0
  390. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/config/__init__.py +0 -0
  391. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/config/crypto.py +0 -0
  392. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/config/loader.py +0 -0
  393. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/config_generator.py +0 -0
  394. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/constraints/__init__.py +0 -0
  395. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/constraints/constraint_deletion.py +0 -0
  396. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/constraints/constraint_id.py +0 -0
  397. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/constraints/frontend_instructions.py +0 -0
  398. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/discovery/__init__.py +0 -0
  399. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/discovery/scanner.py +0 -0
  400. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/generation/__init__.py +0 -0
  401. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/generation/agent_wiring.py +0 -0
  402. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/generation/errors.py +0 -0
  403. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/generation/existing_config.py +0 -0
  404. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/generation/profiler.py +0 -0
  405. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/generation/response_parser.py +0 -0
  406. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/generation/service.py +0 -0
  407. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/models.py +0 -0
  408. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/providers/base.py +0 -0
  409. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/providers/cached_provider.py +0 -0
  410. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/providers/ollama.py +0 -0
  411. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/providers/openai.py +0 -0
  412. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/schema_resolver.py +0 -0
  413. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/suggestion_utils.py +0 -0
  414. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/validate_executor.py +0 -0
  415. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/llm/yaml_io.py +0 -0
  416. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/preview/__init__.py +0 -0
  417. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/preview/loader.py +0 -0
  418. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/preview/path_validation.py +0 -0
  419. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/project_loader.py +0 -0
  420. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/schema_inference.py +0 -0
  421. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/schema_runtime_builder.py +0 -0
  422. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/__init__.py +0 -0
  423. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/chunked_loader.py +0 -0
  424. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/dag/__init__.py +0 -0
  425. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/dag/builder.py +0 -0
  426. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/dag/executor.py +0 -0
  427. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/dag/sorter.py +0 -0
  428. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/data_loader.py +0 -0
  429. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/engine.py +0 -0
  430. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/executor.py +0 -0
  431. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/extractors.py +0 -0
  432. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/history.py +0 -0
  433. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/json_payload.py +0 -0
  434. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/loader.py +0 -0
  435. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/memory_monitor.py +0 -0
  436. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/postprocess.py +0 -0
  437. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/progress.py +0 -0
  438. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/report_export.py +0 -0
  439. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/resolver.py +0 -0
  440. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/service.py +0 -0
  441. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/types.py +0 -0
  442. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/validators/__init__.py +0 -0
  443. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/validators/adapter.py +0 -0
  444. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/validators/base.py +0 -0
  445. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/validators/composite.py +0 -0
  446. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/shared/services/validation/validators/date_logic.py +0 -0
  447. {precis_cli-0.1.6 → precis_cli-0.1.7}/app/start_server.py +0 -0
  448. {precis_cli-0.1.6 → precis_cli-0.1.7}/precis_cli.egg-info/dependency_links.txt +0 -0
  449. {precis_cli-0.1.6 → precis_cli-0.1.7}/precis_cli.egg-info/entry_points.txt +0 -0
  450. {precis_cli-0.1.6 → precis_cli-0.1.7}/precis_cli.egg-info/requires.txt +0 -0
  451. {precis_cli-0.1.6 → precis_cli-0.1.7}/precis_cli.egg-info/top_level.txt +0 -0
  452. {precis_cli-0.1.6 → precis_cli-0.1.7}/setup.cfg +0 -0
  453. {precis_cli-0.1.6 → precis_cli-0.1.7}/tests/test_local_file_reporter.py +0 -0
  454. {precis_cli-0.1.6 → precis_cli-0.1.7}/tests/test_schema_builder.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: precis-cli
3
- Version: 0.1.6
3
+ Version: 0.1.7
4
4
  Summary: Precis - 可配置数据校验工具 CLI(校验 CSV/Excel/JSON 数据质量)
5
5
  Author: Precis Team
6
6
  License: Apache-2.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-v4-pro
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(400, detail=f"不支持的 AI 服务类型「{req.type}」,目前仅支持 openai、ollama 两种接入方式")
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:
@@ -576,7 +576,7 @@ providers:
576
576
  type: openai
577
577
  base_url: https://api.deepseek.com
578
578
  api_key: sk-xxx
579
- model: deepseek-v4-flash
579
+ model: deepseek-flash
580
580
 
581
581
  # 本地 Ollama(无需 API Key)
582
582
  - id: ollama-local
@@ -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
- validation_settings = context.project_config.get("validation", {}) if context.project_config else {}
241
- script_security = context.project_config.get("script_security", {}) if context.project_config else {}
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
- 使用默认设置(timeout=30, 安全沙箱)。
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
- return self._run_validation(manifest_path, data_dir, table_name, {}, {}, output_format, parsed["report"])
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), `thenValue` (Any)。
210
- - `ifConditions` 结构:`[{{"ifColumnId": "列名", "operator": "eq/ne/gt/lt/in", "value": "比较值"}}]`
211
- - **DateLogic**: 日期逻辑约束。参数:`logicMode` ("compare"/"calculation"), `compareOp` ("gt/lt/eq/gte/lte/range"), `referenceDate` (str, "YYYY-MM-DD"), `referenceColumn` (str)。当 `compareOp` 为 "range" 时,必须同时提供 `referenceDateEnd` 或 `referenceColumnEnd`。
212
- - **Charset**: 字符集约束。
213
- - **Composite**: 组合约束(多列联合)。
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}")
@@ -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 range 模式参数完整性检查(不依赖 required_params)
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 = target_column or target_column_id or "unknown"
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
- if not column_id:
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
- inline_constraint = {
318
- "id": constraint_id,
319
- "column": column_id,
320
- "type": std_type,
321
- }
322
- params = _build_constraint_params(std_type, constraint_spec)
323
- if params:
324
- inline_constraint["params"] = params
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
- if existing.get("column") == column_id and existing.get("type") == std_type:
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(std_type, constraint_spec),
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条) 不一致,