precis-cli 0.1.3__py3-none-any.whl

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 (442) hide show
  1. app/__init__.py +16 -0
  2. app/api/__init__.py +32 -0
  3. app/api/dependencies.py +185 -0
  4. app/api/main.py +301 -0
  5. app/api/middleware/__init__.py +34 -0
  6. app/api/middleware/exception_handler.py +126 -0
  7. app/api/middleware/request_logging.py +97 -0
  8. app/api/middleware/token_auth.py +215 -0
  9. app/api/models/__init__.py +151 -0
  10. app/api/models/connection_rules.py +98 -0
  11. app/api/models/files.py +99 -0
  12. app/api/models/full_validation.py +554 -0
  13. app/api/models/project.py +117 -0
  14. app/api/models/projects.py +80 -0
  15. app/api/models/schema.py +121 -0
  16. app/api/models/v2_responses.py +46 -0
  17. app/api/models/validation.py +303 -0
  18. app/api/models/workspace.py +118 -0
  19. app/api/routers/__init__.py +56 -0
  20. app/api/routers/ai/__init__.py +36 -0
  21. app/api/routers/ai/chat.py +243 -0
  22. app/api/routers/ai/generate.py +156 -0
  23. app/api/routers/ai/hardware.py +199 -0
  24. app/api/routers/ai/jobs.py +544 -0
  25. app/api/routers/ai/migrate.py +471 -0
  26. app/api/routers/ai/models.py +352 -0
  27. app/api/routers/ai/ollama.py +108 -0
  28. app/api/routers/ai/providers.py +491 -0
  29. app/api/routers/ai/router.py +44 -0
  30. app/api/routers/ai/stream.py +281 -0
  31. app/api/routers/ai/utils.py +182 -0
  32. app/api/routers/core/__init__.py +34 -0
  33. app/api/routers/core/connection_rules.py +188 -0
  34. app/api/routers/core/data_sources.py +374 -0
  35. app/api/routers/core/regex.py +333 -0
  36. app/api/routers/core/reporting.py +263 -0
  37. app/api/routers/files/__init__.py +24 -0
  38. app/api/routers/files/ops.py +179 -0
  39. app/api/routers/files/transfer.py +101 -0
  40. app/api/routers/preview/__init__.py +35 -0
  41. app/api/routers/preview/content_mode.py +264 -0
  42. app/api/routers/preview/header_row.py +154 -0
  43. app/api/routers/preview/models.py +81 -0
  44. app/api/routers/preview/path_mode.py +440 -0
  45. app/api/routers/preview/router.py +30 -0
  46. app/api/routers/project/__init__.py +61 -0
  47. app/api/routers/project/base.py +111 -0
  48. app/api/routers/project/constraint.py +345 -0
  49. app/api/routers/project/full_config.py +411 -0
  50. app/api/routers/project/full_config_writer.py +327 -0
  51. app/api/routers/project/helpers.py +167 -0
  52. app/api/routers/project/inspection_fix.py +330 -0
  53. app/api/routers/project/manifest.py +605 -0
  54. app/api/routers/project/models.py +177 -0
  55. app/api/routers/project/pattern.py +268 -0
  56. app/api/routers/project/regex.py +358 -0
  57. app/api/routers/project/scanner.py +157 -0
  58. app/api/routers/project/schema.py +567 -0
  59. app/api/routers/project/schema_helpers.py +149 -0
  60. app/api/routers/project/settings.py +399 -0
  61. app/api/routers/project/template.py +325 -0
  62. app/api/routers/project/validation.py +227 -0
  63. app/api/routers/project/view.py +177 -0
  64. app/api/routers/project/workspaces.py +167 -0
  65. app/api/routers/projects/__init__.py +25 -0
  66. app/api/routers/projects/create.py +121 -0
  67. app/api/routers/projects/open.py +103 -0
  68. app/api/routers/projects/scan.py +100 -0
  69. app/api/routers/validation/__init__.py +39 -0
  70. app/api/routers/validation/common.py +263 -0
  71. app/api/routers/validation/content_mode.py +401 -0
  72. app/api/routers/validation/history.py +235 -0
  73. app/api/routers/validation/inline_mode.py +196 -0
  74. app/api/routers/validation/path_mode.py +314 -0
  75. app/api/routers/validation/router.py +51 -0
  76. app/api/services/full_validation_response_builder.py +412 -0
  77. app/api/services/io_error_messages.py +41 -0
  78. app/api/services/preview_service.py +248 -0
  79. app/cli/__init__.py +18 -0
  80. app/cli/__main__.py +30 -0
  81. app/cli/shared_services/__init__.py +42 -0
  82. app/cli/shared_services/config_ops.py +581 -0
  83. app/cli/shared_services/generation_ops.py +160 -0
  84. app/cli/shared_services/project_ops.py +288 -0
  85. app/cli/shell/__init__.py +48 -0
  86. app/cli/shell/commands/__init__.py +63 -0
  87. app/cli/shell/commands/ai/__init__.py +260 -0
  88. app/cli/shell/commands/ai/chat.py +331 -0
  89. app/cli/shell/commands/ai/delete.py +165 -0
  90. app/cli/shell/commands/ai/diff.py +70 -0
  91. app/cli/shell/commands/ai/display.py +428 -0
  92. app/cli/shell/commands/ai/executor.py +225 -0
  93. app/cli/shell/commands/ai/executor_utils.py +271 -0
  94. app/cli/shell/commands/ai/generate.py +285 -0
  95. app/cli/shell/commands/ai/interaction.py +262 -0
  96. app/cli/shell/commands/ai/migrate.py +281 -0
  97. app/cli/shell/commands/ai/resolver.py +224 -0
  98. app/cli/shell/commands/ai/status.py +101 -0
  99. app/cli/shell/commands/ai/switch.py +158 -0
  100. app/cli/shell/commands/ai/utils.py +52 -0
  101. app/cli/shell/commands/base.py +343 -0
  102. app/cli/shell/commands/config/__init__.py +131 -0
  103. app/cli/shell/commands/config/base.py +80 -0
  104. app/cli/shell/commands/config/check.py +246 -0
  105. app/cli/shell/commands/config/edit.py +148 -0
  106. app/cli/shell/commands/config/get.py +111 -0
  107. app/cli/shell/commands/config/init.py +123 -0
  108. app/cli/shell/commands/config/inspect.py +164 -0
  109. app/cli/shell/commands/config/list.py +104 -0
  110. app/cli/shell/commands/config/set.py +119 -0
  111. app/cli/shell/commands/config/show.py +150 -0
  112. app/cli/shell/commands/exit.py +67 -0
  113. app/cli/shell/commands/help.py +104 -0
  114. app/cli/shell/commands/infer_schema.py +156 -0
  115. app/cli/shell/commands/open.py +201 -0
  116. app/cli/shell/commands/project.py +215 -0
  117. app/cli/shell/commands/provider.py +619 -0
  118. app/cli/shell/commands/system.py +170 -0
  119. app/cli/shell/commands/validate.py +455 -0
  120. app/cli/shell/completer.py +231 -0
  121. app/cli/shell/config_storage.py +191 -0
  122. app/cli/shell/exceptions.py +90 -0
  123. app/cli/shell/formatter.py +371 -0
  124. app/cli/shell/interactive_menu.py +348 -0
  125. app/cli/shell/main.py +286 -0
  126. app/cli/shell/parser.py +266 -0
  127. app/cli/start.py +180 -0
  128. app/cli_main.py +52 -0
  129. app/mcp_server.py +311 -0
  130. app/shared/core/__init__.py +18 -0
  131. app/shared/core/app_version.py +59 -0
  132. app/shared/core/config/__init__.py +119 -0
  133. app/shared/core/config/server.py +193 -0
  134. app/shared/core/data_source/__init__.py +106 -0
  135. app/shared/core/data_source/loader.py +348 -0
  136. app/shared/core/data_source/loaders/__init__.py +213 -0
  137. app/shared/core/data_source/loaders/base.py +215 -0
  138. app/shared/core/data_source/loaders/converter.py +337 -0
  139. app/shared/core/data_source/loaders/csv_loader.py +252 -0
  140. app/shared/core/data_source/loaders/excel_loader.py +666 -0
  141. app/shared/core/data_source/loaders/extractor.py +268 -0
  142. app/shared/core/data_source/loaders/json_loader.py +354 -0
  143. app/shared/core/data_source/loaders/registry.py +88 -0
  144. app/shared/core/data_source/loaders/sql_loader.py +313 -0
  145. app/shared/core/data_source/loaders/strategies/__init__.py +100 -0
  146. app/shared/core/data_source/loaders/strategies/array_parser.py +277 -0
  147. app/shared/core/data_source/loaders/strategies/lines_parser.py +355 -0
  148. app/shared/core/data_source/loaders/strategies/object_parser.py +278 -0
  149. app/shared/core/data_source/schema_info.py +50 -0
  150. app/shared/core/data_source/specs/__init__.py +128 -0
  151. app/shared/core/data_source/specs/base.py +258 -0
  152. app/shared/core/data_source/specs/csv_source.py +137 -0
  153. app/shared/core/data_source/specs/excel_source.py +141 -0
  154. app/shared/core/data_source/specs/file_base.py +252 -0
  155. app/shared/core/data_source/specs/json_source.py +226 -0
  156. app/shared/core/data_source/specs/sql_source.py +161 -0
  157. app/shared/core/encoding.py +36 -0
  158. app/shared/core/io/__init__.py +24 -0
  159. app/shared/core/io/yaml.py +379 -0
  160. app/shared/core/manifest_schema/__init__.py +52 -0
  161. app/shared/core/manifest_schema/types.py +99 -0
  162. app/shared/core/manifest_schema/version.py +175 -0
  163. app/shared/core/patterns/__init__.py +24 -0
  164. app/shared/core/patterns/loader.py +134 -0
  165. app/shared/core/patterns/writer.py +244 -0
  166. app/shared/core/project/__init__.py +47 -0
  167. app/shared/core/project/constraint/builders/__init__.py +50 -0
  168. app/shared/core/project/constraint/builders/base.py +100 -0
  169. app/shared/core/project/constraint/builders/composite.py +77 -0
  170. app/shared/core/project/constraint/builders/conditional.py +67 -0
  171. app/shared/core/project/constraint/builders/foreign_key.py +53 -0
  172. app/shared/core/project/constraint/builders/registry.py +64 -0
  173. app/shared/core/project/constraint/builders/scripted.py +51 -0
  174. app/shared/core/project/constraint/builders/single_column.py +86 -0
  175. app/shared/core/project/constraint/builders/unique.py +53 -0
  176. app/shared/core/project/constraint/factory.py +170 -0
  177. app/shared/core/project/constraint/reader.py +214 -0
  178. app/shared/core/project/constraint/registry.py +233 -0
  179. app/shared/core/project/constraint/types/__init__.py +63 -0
  180. app/shared/core/project/constraint/types/constraint_file.py +261 -0
  181. app/shared/core/project/constraint/types/refs.py +460 -0
  182. app/shared/core/project/constraint/types.py +28 -0
  183. app/shared/core/project/constraint/writer.py +181 -0
  184. app/shared/core/project/loader/__init__.py +56 -0
  185. app/shared/core/project/loader/loader.py +30 -0
  186. app/shared/core/project/loader/loader_parts/config_inspector.py +137 -0
  187. app/shared/core/project/loader/loader_parts/embedded_constraints.py +224 -0
  188. app/shared/core/project/loader/loader_parts/file_loaders.py +58 -0
  189. app/shared/core/project/loader/loader_parts/inspection_ids.py +85 -0
  190. app/shared/core/project/loader/loader_parts/inspector_helpers.py +312 -0
  191. app/shared/core/project/loader/loader_parts/inspector_id_checks.py +274 -0
  192. app/shared/core/project/loader/loader_parts/inspector_reference_checks.py +690 -0
  193. app/shared/core/project/loader/loader_parts/inspector_uniqueness_checks.py +286 -0
  194. app/shared/core/project/loader/loader_parts/loading_error_messages.py +298 -0
  195. app/shared/core/project/loader/loader_parts/main.py +432 -0
  196. app/shared/core/project/loader/loader_parts/path_validation.py +117 -0
  197. app/shared/core/project/loader/loader_parts/runtime.py +125 -0
  198. app/shared/core/project/loader/types.py +246 -0
  199. app/shared/core/project/manifest/coverage.py +391 -0
  200. app/shared/core/project/manifest/reader.py +260 -0
  201. app/shared/core/project/manifest/types.py +91 -0
  202. app/shared/core/project/manifest/types_parts/__init__.py +60 -0
  203. app/shared/core/project/manifest/types_parts/constants.py +40 -0
  204. app/shared/core/project/manifest/types_parts/data_source.py +68 -0
  205. app/shared/core/project/manifest/types_parts/info.py +59 -0
  206. app/shared/core/project/manifest/types_parts/manifest.py +294 -0
  207. app/shared/core/project/manifest/types_parts/refs.py +153 -0
  208. app/shared/core/project/manifest/types_parts/settings.py +92 -0
  209. app/shared/core/project/manifest/types_parts/settings_file_processing.py +64 -0
  210. app/shared/core/project/manifest/types_parts/settings_script_security.py +78 -0
  211. app/shared/core/project/manifest/types_parts/settings_validation.py +83 -0
  212. app/shared/core/project/manifest/types_parts/template.py +66 -0
  213. app/shared/core/project/manifest/writer.py +262 -0
  214. app/shared/core/project/manual_data/__init__.py +27 -0
  215. app/shared/core/project/manual_data/types.py +75 -0
  216. app/shared/core/project/regex/reader.py +197 -0
  217. app/shared/core/project/regex/types.py +405 -0
  218. app/shared/core/project/regex/writer.py +123 -0
  219. app/shared/core/project/schema/reader.py +170 -0
  220. app/shared/core/project/schema/types.py +47 -0
  221. app/shared/core/project/schema/types_parts/__init__.py +36 -0
  222. app/shared/core/project/schema/types_parts/column.py +174 -0
  223. app/shared/core/project/schema/types_parts/column_utils.py +72 -0
  224. app/shared/core/project/schema/types_parts/constraint.py +165 -0
  225. app/shared/core/project/schema/types_parts/schema_id.py +66 -0
  226. app/shared/core/project/schema/types_parts/source.py +255 -0
  227. app/shared/core/project/schema/types_parts/source_options.py +347 -0
  228. app/shared/core/project/schema/types_parts/table.py +230 -0
  229. app/shared/core/project/schema/writer.py +139 -0
  230. app/shared/core/project/schema_ref_check.py +95 -0
  231. app/shared/core/project/template/__init__.py +27 -0
  232. app/shared/core/project/template/expander.py +263 -0
  233. app/shared/core/project/template/reader.py +120 -0
  234. app/shared/core/project/template/types.py +114 -0
  235. app/shared/core/project/transform/reader.py +76 -0
  236. app/shared/core/project/transform/types.py +116 -0
  237. app/shared/core/project/transform/writer.py +84 -0
  238. app/shared/core/pydantic_messages.py +59 -0
  239. app/shared/core/reporter/__init__.py +46 -0
  240. app/shared/core/reporter/reporter.py +220 -0
  241. app/shared/core/reporter/reporters/__init__.py +65 -0
  242. app/shared/core/reporter/reporters/base.py +188 -0
  243. app/shared/core/reporter/reporters/dingtalk_app_reporter.py +274 -0
  244. app/shared/core/reporter/reporters/email_reporter.py +271 -0
  245. app/shared/core/reporter/reporters/feishu_app_reporter.py +467 -0
  246. app/shared/core/reporter/reporters/local_file_reporter.py +208 -0
  247. app/shared/core/reporter/reporters/wecom_app_reporter.py +268 -0
  248. app/shared/core/utils/__init__.py +18 -0
  249. app/shared/core/utils/path_utils.py +60 -0
  250. app/shared/core/utils/regex_extract.py +113 -0
  251. app/shared/domain/__init__.py +114 -0
  252. app/shared/domain/constraints/__init__.py +76 -0
  253. app/shared/domain/constraints/allowed_values.py +211 -0
  254. app/shared/domain/constraints/base.py +141 -0
  255. app/shared/domain/constraints/charset.py +337 -0
  256. app/shared/domain/constraints/composite.py +174 -0
  257. app/shared/domain/constraints/condition_registry.py +130 -0
  258. app/shared/domain/constraints/conditional.py +629 -0
  259. app/shared/domain/constraints/date_logic.py +731 -0
  260. app/shared/domain/constraints/foreign_key.py +261 -0
  261. app/shared/domain/constraints/key_normalization.py +56 -0
  262. app/shared/domain/constraints/not_null.py +185 -0
  263. app/shared/domain/constraints/range.py +360 -0
  264. app/shared/domain/constraints/regex.py +218 -0
  265. app/shared/domain/constraints/scripted.py +276 -0
  266. app/shared/domain/constraints/unique.py +233 -0
  267. app/shared/domain/data_engine.py +384 -0
  268. app/shared/domain/data_types.py +113 -0
  269. app/shared/domain/data_types_parts/__init__.py +67 -0
  270. app/shared/domain/data_types_parts/base.py +204 -0
  271. app/shared/domain/data_types_parts/composite.py +250 -0
  272. app/shared/domain/data_types_parts/expression.py +202 -0
  273. app/shared/domain/data_types_parts/extracted.py +106 -0
  274. app/shared/domain/data_types_parts/json_types.py +234 -0
  275. app/shared/domain/data_types_parts/scalars.py +719 -0
  276. app/shared/domain/data_types_parts/sequence.py +129 -0
  277. app/shared/domain/dataset_schema.py +48 -0
  278. app/shared/domain/eval_sandbox.py +63 -0
  279. app/shared/domain/expression_system.py +366 -0
  280. app/shared/domain/regex_flags.py +53 -0
  281. app/shared/domain/schema/builder.py +223 -0
  282. app/shared/domain/schema/models.py +339 -0
  283. app/shared/domain/transforms/__init__.py +28 -0
  284. app/shared/domain/transforms/aggregate.py +141 -0
  285. app/shared/domain/transforms/base.py +171 -0
  286. app/shared/domain/transforms/cast_type.py +120 -0
  287. app/shared/domain/transforms/concat.py +103 -0
  288. app/shared/domain/transforms/conditional_assign.py +114 -0
  289. app/shared/domain/transforms/date_format.py +81 -0
  290. app/shared/domain/transforms/digits.py +77 -0
  291. app/shared/domain/transforms/drop_duplicates.py +94 -0
  292. app/shared/domain/transforms/fill_na.py +94 -0
  293. app/shared/domain/transforms/filter_rows.py +97 -0
  294. app/shared/domain/transforms/lookup.py +78 -0
  295. app/shared/domain/transforms/lower_case.py +70 -0
  296. app/shared/domain/transforms/map_value.py +90 -0
  297. app/shared/domain/transforms/math_expr.py +112 -0
  298. app/shared/domain/transforms/modulo.py +82 -0
  299. app/shared/domain/transforms/regex_extract.py +103 -0
  300. app/shared/domain/transforms/registry.py +95 -0
  301. app/shared/domain/transforms/replace.py +88 -0
  302. app/shared/domain/transforms/sort_rows.py +94 -0
  303. app/shared/domain/transforms/string_split.py +84 -0
  304. app/shared/domain/transforms/strip.py +73 -0
  305. app/shared/domain/transforms/substring.py +92 -0
  306. app/shared/domain/transforms/upper_case.py +70 -0
  307. app/shared/domain/transforms/weighted_sum.py +104 -0
  308. app/shared/domain/validation_constraints.py +69 -0
  309. app/shared/services/__init__.py +62 -0
  310. app/shared/services/ai/__init__.py +48 -0
  311. app/shared/services/ai/agent/__init__.py +40 -0
  312. app/shared/services/ai/agent/chat_tools/__init__.py +47 -0
  313. app/shared/services/ai/agent/chat_tools/apply_actions.py +592 -0
  314. app/shared/services/ai/agent/chat_tools/ask_user.py +237 -0
  315. app/shared/services/ai/agent/chat_tools/read_canvas.py +140 -0
  316. app/shared/services/ai/agent/chat_tools/read_project.py +160 -0
  317. app/shared/services/ai/agent/chat_tools/read_table.py +301 -0
  318. app/shared/services/ai/agent/chat_tools/schemas.py +105 -0
  319. app/shared/services/ai/agent/chat_tools/validate_table.py +131 -0
  320. app/shared/services/ai/agent/executor.py +554 -0
  321. app/shared/services/ai/agent/memory.py +256 -0
  322. app/shared/services/ai/agent/planner.py +282 -0
  323. app/shared/services/ai/agent/tool_registry.py +296 -0
  324. app/shared/services/ai/agent/tools/__init__.py +32 -0
  325. app/shared/services/ai/agent/tools/config_generate.py +133 -0
  326. app/shared/services/ai/agent/tools/config_refine.py +109 -0
  327. app/shared/services/ai/agent/tools/config_validate.py +403 -0
  328. app/shared/services/ai/agent/tools/merge_results.py +136 -0
  329. app/shared/services/ai/agent/tools/plan_chunks.py +79 -0
  330. app/shared/services/ai/agent/tools/script_parse.py +359 -0
  331. app/shared/services/ai/agent/types.py +138 -0
  332. app/shared/services/ai/chat_agent_runner.py +596 -0
  333. app/shared/services/ai/chat_orchestrator.py +725 -0
  334. app/shared/services/ai/failure_messages.py +65 -0
  335. app/shared/services/ai/job_storage.py +274 -0
  336. app/shared/services/ai/migrate_service.py +550 -0
  337. app/shared/services/ai/streaming/__init__.py +65 -0
  338. app/shared/services/ai/streaming/event_journal.py +197 -0
  339. app/shared/services/ai/streaming/orchestrator.py +262 -0
  340. app/shared/services/ai/streaming/pending_interaction_store.py +227 -0
  341. app/shared/services/ai/streaming/sse_response.py +148 -0
  342. app/shared/services/ai/streaming/types.py +73 -0
  343. app/shared/services/ai/types.py +213 -0
  344. app/shared/services/ai/utils.py +322 -0
  345. app/shared/services/diff/config_diff.py +320 -0
  346. app/shared/services/hardware.py +237 -0
  347. app/shared/services/llm/__init__.py +62 -0
  348. app/shared/services/llm/actions/__init__.py +42 -0
  349. app/shared/services/llm/actions/_canvas_validator.py +147 -0
  350. app/shared/services/llm/actions/_constraint_validator.py +401 -0
  351. app/shared/services/llm/actions/_regex_validator.py +85 -0
  352. app/shared/services/llm/actions/_schema_validator.py +82 -0
  353. app/shared/services/llm/actions/_settings_validator.py +76 -0
  354. app/shared/services/llm/actions/_transform_validator.py +78 -0
  355. app/shared/services/llm/actions/action_handlers.py +400 -0
  356. app/shared/services/llm/actions/action_parser.py +63 -0
  357. app/shared/services/llm/actions/action_processor.py +468 -0
  358. app/shared/services/llm/actions/action_validator.py +311 -0
  359. app/shared/services/llm/actions/diff_compute.py +195 -0
  360. app/shared/services/llm/actions/regex_handlers.py +284 -0
  361. app/shared/services/llm/actions/registry.py +336 -0
  362. app/shared/services/llm/actions/schema_handlers.py +335 -0
  363. app/shared/services/llm/actions/settings_handlers.py +180 -0
  364. app/shared/services/llm/actions/specs.py +259 -0
  365. app/shared/services/llm/actions/transform_handlers.py +279 -0
  366. app/shared/services/llm/actions/validation_types.py +147 -0
  367. app/shared/services/llm/cache/__init__.py +18 -0
  368. app/shared/services/llm/cache/response_cache.py +80 -0
  369. app/shared/services/llm/chat/__init__.py +35 -0
  370. app/shared/services/llm/chat/chat_system_prompt.py +561 -0
  371. app/shared/services/llm/chat/response_parser.py +296 -0
  372. app/shared/services/llm/config/__init__.py +45 -0
  373. app/shared/services/llm/config/crypto.py +135 -0
  374. app/shared/services/llm/config/loader.py +258 -0
  375. app/shared/services/llm/config/models.py +202 -0
  376. app/shared/services/llm/config/presets.py +128 -0
  377. app/shared/services/llm/config_generator.py +163 -0
  378. app/shared/services/llm/constraints/__init__.py +41 -0
  379. app/shared/services/llm/constraints/constraint_builder.py +177 -0
  380. app/shared/services/llm/constraints/constraint_deletion.py +84 -0
  381. app/shared/services/llm/constraints/constraint_id.py +174 -0
  382. app/shared/services/llm/constraints/frontend_instructions.py +333 -0
  383. app/shared/services/llm/constraints/inline_batch.py +279 -0
  384. app/shared/services/llm/discovery/__init__.py +35 -0
  385. app/shared/services/llm/discovery/scanner.py +181 -0
  386. app/shared/services/llm/generation/__init__.py +42 -0
  387. app/shared/services/llm/generation/agent_wiring.py +156 -0
  388. app/shared/services/llm/generation/config_builder.py +386 -0
  389. app/shared/services/llm/generation/errors.py +36 -0
  390. app/shared/services/llm/generation/existing_config.py +99 -0
  391. app/shared/services/llm/generation/profiler.py +279 -0
  392. app/shared/services/llm/generation/prompt_builder.py +199 -0
  393. app/shared/services/llm/generation/response_parser.py +144 -0
  394. app/shared/services/llm/generation/service.py +622 -0
  395. app/shared/services/llm/models.py +104 -0
  396. app/shared/services/llm/providers/__init__.py +48 -0
  397. app/shared/services/llm/providers/base.py +310 -0
  398. app/shared/services/llm/providers/cached_provider.py +90 -0
  399. app/shared/services/llm/providers/ollama.py +498 -0
  400. app/shared/services/llm/providers/openai.py +334 -0
  401. app/shared/services/llm/providers/registry.py +108 -0
  402. app/shared/services/llm/schema_resolver.py +141 -0
  403. app/shared/services/llm/suggestion_utils.py +219 -0
  404. app/shared/services/llm/validate_executor.py +163 -0
  405. app/shared/services/llm/yaml_io.py +406 -0
  406. app/shared/services/preview/__init__.py +18 -0
  407. app/shared/services/preview/loader.py +145 -0
  408. app/shared/services/preview/path_validation.py +138 -0
  409. app/shared/services/project_loader.py +57 -0
  410. app/shared/services/schema_inference.py +260 -0
  411. app/shared/services/schema_runtime_builder.py +120 -0
  412. app/shared/services/validation/__init__.py +52 -0
  413. app/shared/services/validation/chunked_loader.py +509 -0
  414. app/shared/services/validation/dag/__init__.py +35 -0
  415. app/shared/services/validation/dag/builder.py +141 -0
  416. app/shared/services/validation/dag/executor.py +225 -0
  417. app/shared/services/validation/dag/sorter.py +77 -0
  418. app/shared/services/validation/data_loader.py +231 -0
  419. app/shared/services/validation/engine.py +446 -0
  420. app/shared/services/validation/executor.py +1030 -0
  421. app/shared/services/validation/extractors.py +266 -0
  422. app/shared/services/validation/history.py +209 -0
  423. app/shared/services/validation/json_payload.py +136 -0
  424. app/shared/services/validation/loader.py +152 -0
  425. app/shared/services/validation/memory_monitor.py +179 -0
  426. app/shared/services/validation/postprocess.py +208 -0
  427. app/shared/services/validation/progress.py +64 -0
  428. app/shared/services/validation/report_export.py +222 -0
  429. app/shared/services/validation/resolver.py +180 -0
  430. app/shared/services/validation/service.py +418 -0
  431. app/shared/services/validation/types.py +238 -0
  432. app/shared/services/validation/validators/__init__.py +36 -0
  433. app/shared/services/validation/validators/adapter.py +182 -0
  434. app/shared/services/validation/validators/base.py +332 -0
  435. app/shared/services/validation/validators/composite.py +233 -0
  436. app/shared/services/validation/validators/date_logic.py +276 -0
  437. app/start_server.py +133 -0
  438. precis_cli-0.1.3.dist-info/METADATA +180 -0
  439. precis_cli-0.1.3.dist-info/RECORD +442 -0
  440. precis_cli-0.1.3.dist-info/WHEEL +5 -0
  441. precis_cli-0.1.3.dist-info/entry_points.txt +4 -0
  442. precis_cli-0.1.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,550 @@
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 AI 配置迁移服务
17
+
18
+ 功能概述:
19
+ - 从旧脚本(Python pandas / 自然语言 / Excel 公式 / SQL)迁移生成 Precis V2 配置
20
+ - 复用 Agent 内核和配置生成/校验/精修工具
21
+
22
+ 架构设计:
23
+ - 使用 AgentExecutor + ToolRegistry
24
+ - script_parse 工具解析意图
25
+ - generate_config 工具根据意图生成配置
26
+ - validate_config / refine_config 校验和精修
27
+ """
28
+
29
+ from __future__ import annotations
30
+
31
+ import asyncio
32
+ import logging
33
+ from collections.abc import Callable
34
+ from typing import Any
35
+
36
+ from app.shared.services.ai.agent import AgentExecutor
37
+ from app.shared.services.ai.agent.planner import build_source_chunk_plan
38
+ from app.shared.services.ai.agent.tool_registry import ToolRegistry
39
+ from app.shared.services.ai.agent.tools import (
40
+ ConfigGenerateTool,
41
+ ConfigRefineTool,
42
+ ConfigValidateTool,
43
+ MergeResultsTool,
44
+ PlanChunksTool,
45
+ ScriptParseTool,
46
+ )
47
+ from app.shared.services.llm.generation import CancelledError, GenerationOptions, ProfilingOptions
48
+ from app.shared.services.llm.generation.service import ConfigGenerationService
49
+
50
+ logger = logging.getLogger(__name__)
51
+
52
+
53
+ class ConfigMigrationService(ConfigGenerationService):
54
+ """
55
+ @classdesc 配置迁移服务
56
+
57
+ 从旧脚本迁移生成 Precis 配置,支持单脚本或批量脚本合并。
58
+ """
59
+
60
+ async def migrate_from_script(
61
+ self,
62
+ script_content: str,
63
+ language: str,
64
+ file_paths: list[str],
65
+ project_name: str,
66
+ project_id: str,
67
+ config_path: str | None = None,
68
+ profiling_options: ProfilingOptions | None = None,
69
+ generation_options: GenerationOptions | None = None,
70
+ max_iterations: int = 2,
71
+ validation_sample_size: int = 1000,
72
+ progress_callback: Callable[..., Any] | None = None,
73
+ checkpoint_callback: Callable[..., Any] | None = None,
74
+ sources: list[dict[str, Any]] | None = None,
75
+ initial_checkpoint: dict[str, Any] | None = None,
76
+ chunk_max_sources: int = 5,
77
+ chunk_max_tokens: int = 8000,
78
+ enable_chunking: bool = True,
79
+ ) -> dict[str, Any]:
80
+ """
81
+ @methoddesc 从脚本迁移生成配置
82
+
83
+ 参数:
84
+ script_content: 脚本内容(单来源兼容字段)
85
+ language: 脚本类型
86
+ file_paths: 数据文件路径
87
+ project_name: 项目名称
88
+ project_id: 项目标识
89
+ config_path: 项目配置路径
90
+ profiling_options: 画像选项
91
+ generation_options: 生成选项
92
+ max_iterations: 最大迭代轮数
93
+ validation_sample_size: 校验采样数
94
+ progress_callback: 进度回调(stage, progress, extra)
95
+ checkpoint_callback: checkpoint 回调
96
+ sources: 批量脚本来源列表,每个元素含 content/language/name
97
+ chunk_max_sources: 每个分片最大来源数
98
+ chunk_max_tokens: 每个分片最大估算 token 数
99
+ enable_chunking: 是否启用按源分片
100
+
101
+ 返回:
102
+ 完整配置字典
103
+ """
104
+ self._setup_run(
105
+ file_paths=file_paths,
106
+ project_name=project_name,
107
+ project_id=project_id,
108
+ config_path=config_path,
109
+ profiling_options=profiling_options,
110
+ generation_options=generation_options,
111
+ )
112
+
113
+ self._profiling_data = await self._profile_files(file_paths, self._profiling_options)
114
+ if self._generation_options.keep_existing and config_path:
115
+ self._existing_config = self._load_existing_config(config_path)
116
+
117
+ # 统一转换为批量来源;若 script_content 与 sources 中首个内容相同,避免重复解析
118
+ migrate_sources: list[dict[str, Any]] = []
119
+ seen_contents = set()
120
+ if sources:
121
+ for s in sources:
122
+ if not isinstance(s, dict) or not s.get("content"):
123
+ continue
124
+ content = s["content"].strip()
125
+ if content in seen_contents:
126
+ continue
127
+ seen_contents.add(content)
128
+ migrate_sources.append(
129
+ {
130
+ "content": content,
131
+ "language": s.get("language", language),
132
+ "name": s.get("name") or f"source_{len(migrate_sources) + 1}",
133
+ }
134
+ )
135
+ script_key = script_content.strip()
136
+ if script_key and script_key not in seen_contents:
137
+ migrate_sources.insert(
138
+ 0,
139
+ {"content": script_key, "language": language, "name": "manual_paste"},
140
+ )
141
+
142
+ if not migrate_sources:
143
+ return {
144
+ "success": False,
145
+ "error": "未提供任何脚本内容",
146
+ "yaml_preview": "",
147
+ "manifest": None,
148
+ "schemas": {},
149
+ "constraints": {},
150
+ "regex_nodes": {},
151
+ "warnings": [],
152
+ "iterations": 0,
153
+ }
154
+
155
+ if self._cancelled:
156
+ raise CancelledError()
157
+
158
+ registry = self._create_migrate_registry(validation_sample_size)
159
+
160
+ # 批量解析每个来源的意图
161
+ parsed_intents = []
162
+ total = len(migrate_sources)
163
+ for idx, source in enumerate(migrate_sources):
164
+ if self._cancelled:
165
+ raise CancelledError()
166
+ base_progress = idx / total * 0.4
167
+ if progress_callback:
168
+ progress_callback(
169
+ "parse_script",
170
+ base_progress,
171
+ {"iterations": 0, "current_source": source.get("name") or f"source_{idx + 1}"},
172
+ )
173
+ parse_tool = ScriptParseTool(self)
174
+ intent = parse_tool.run(
175
+ {
176
+ "script_content": source["content"],
177
+ "language": source.get("language", language),
178
+ }
179
+ )
180
+ parsed_intents.append(
181
+ {
182
+ "name": source.get("name") or f"source_{idx + 1}",
183
+ "language": source.get("language", language),
184
+ "intent": intent,
185
+ }
186
+ )
187
+
188
+ # 按源分片规划
189
+ source_plan = build_source_chunk_plan(
190
+ parsed_intents,
191
+ max_sources_per_chunk=chunk_max_sources,
192
+ max_tokens_per_chunk=chunk_max_tokens,
193
+ )
194
+ chunk_total = len(source_plan.chunks)
195
+ if progress_callback:
196
+ progress_callback(
197
+ "source_planning",
198
+ 0.35,
199
+ {"iterations": 0, "chunk_total": chunk_total, "strategy": source_plan.strategy},
200
+ )
201
+
202
+ if not enable_chunking:
203
+ # 显式关闭分片时走原有单次 Agent 路径,保持完全零回归
204
+ return await self._migrate_single(
205
+ parsed_intents,
206
+ registry,
207
+ max_iterations,
208
+ progress_callback,
209
+ checkpoint_callback,
210
+ initial_checkpoint=initial_checkpoint,
211
+ )
212
+
213
+ provider = self._get_provider()
214
+ # get_context_window 内部可能调用 Ollama 的同步 urllib 探测,放到线程池避免阻塞事件循环
215
+ context_window = await asyncio.to_thread(provider.get_context_window)
216
+ max_tokens = max(context_window - 8000, 4096)
217
+
218
+ # 分片生成
219
+ partial_configs: list[dict[str, Any]] = []
220
+ for ci, chunk in enumerate(source_plan.chunks):
221
+ if self._cancelled:
222
+ raise CancelledError()
223
+ chunk_index = ci + 1
224
+ if progress_callback:
225
+ progress_callback(
226
+ "chunk_generate",
227
+ 0.35 + (ci / max(chunk_total, 1)) * 0.45,
228
+ {
229
+ "iterations": len(partial_configs),
230
+ "chunk_index": chunk_index,
231
+ "chunk_total": chunk_total,
232
+ },
233
+ )
234
+
235
+ chunk_intents = [parsed_intents[idx] for idx in chunk.source_indices]
236
+ instructions = self._build_chunk_task_instructions(
237
+ chunk_intents,
238
+ chunk_total,
239
+ chunk_index,
240
+ )
241
+ try:
242
+ partial = await self._generate_for_chunk(instructions, previous_config=None)
243
+ except Exception as e:
244
+ logger.warning(f"分片 {chunk.chunk_id} 生成失败: {e}")
245
+ partial = {}
246
+ if partial.get("schemas") or partial.get("constraints") or partial.get("regex_nodes"):
247
+ partial_configs.append(partial)
248
+
249
+ if not partial_configs:
250
+ return {
251
+ "success": False,
252
+ "error": "未能从脚本中解析出有效配置",
253
+ "yaml_preview": "",
254
+ "manifest": None,
255
+ "schemas": {},
256
+ "constraints": {},
257
+ "regex_nodes": {},
258
+ "warnings": [],
259
+ "iterations": 0,
260
+ }
261
+
262
+ if progress_callback:
263
+ progress_callback(
264
+ "merge_results",
265
+ 0.85,
266
+ {"iterations": len(partial_configs), "merged_chunks": chunk_total},
267
+ )
268
+
269
+ merge_tool = MergeResultsTool()
270
+ merge_result = merge_tool.run({"configs": partial_configs})
271
+ config: dict[str, Any] = merge_result.get("config", {})
272
+ warnings = list(merge_result.get("warnings", []))
273
+
274
+ # 多分片时进行校验 + 精修兜底
275
+ if chunk_total > 1:
276
+ if progress_callback:
277
+ progress_callback(
278
+ "refine_config",
279
+ 0.9,
280
+ {
281
+ "iterations": len(partial_configs),
282
+ "metrics": {
283
+ "schemas": len(config.get("schemas", {})),
284
+ "constraints": len(config.get("constraints", {})),
285
+ },
286
+ },
287
+ )
288
+ try:
289
+ config = await self._optional_refine_via_agent(
290
+ config,
291
+ registry=registry,
292
+ merge_warnings=warnings,
293
+ max_iterations=max_iterations,
294
+ max_tokens=max_tokens,
295
+ progress_callback=progress_callback,
296
+ checkpoint_callback=checkpoint_callback,
297
+ )
298
+ except Exception as e:
299
+ logger.warning(f"精修阶段失败,使用合并结果: {e}")
300
+
301
+ if not config.get("schemas") and not config.get("constraints"):
302
+ return {
303
+ "success": False,
304
+ "error": "未能从脚本中解析出有效配置",
305
+ "yaml_preview": "",
306
+ "manifest": None,
307
+ "schemas": {},
308
+ "constraints": {},
309
+ "regex_nodes": {},
310
+ "warnings": warnings,
311
+ "iterations": len(partial_configs),
312
+ }
313
+
314
+ config["success"] = True
315
+ config["iterations"] = len(partial_configs)
316
+ config["warnings"] = list(config.get("warnings", [])) + warnings
317
+ return config
318
+
319
+ async def _migrate_single(
320
+ self,
321
+ parsed_intents: list[dict[str, Any]],
322
+ registry: ToolRegistry,
323
+ max_iterations: int,
324
+ progress_callback: Callable[..., Any] | None,
325
+ checkpoint_callback: Callable[..., Any] | None,
326
+ initial_checkpoint: dict[str, Any] | None = None,
327
+ ) -> dict[str, Any]:
328
+ """单次 Agent 生成路径(显式关闭分片时的零回归路径)。
329
+
330
+ 支持 initial_checkpoint 续跑(与 generation 路径一致):传入时从断点恢复 memory。
331
+ """
332
+ if progress_callback:
333
+ progress_callback("generate_config", 0.45, {"iterations": 0})
334
+
335
+ provider = self._get_provider()
336
+ context_window = await asyncio.to_thread(provider.get_context_window)
337
+ max_tokens = max(context_window - 8000, 4096)
338
+ executor = AgentExecutor(
339
+ provider=provider,
340
+ registry=registry,
341
+ system_prompt=self._build_migrate_system_prompt(),
342
+ max_iterations=max_iterations,
343
+ max_tokens=max_tokens,
344
+ progress_callback=lambda stage, progress, extra: (
345
+ progress_callback(stage, 0.5 + progress * 0.5, extra) if progress_callback else None
346
+ ),
347
+ checkpoint_callback=checkpoint_callback,
348
+ cancelled_callback=lambda: self._cancelled,
349
+ )
350
+
351
+ task_message = self._build_migrate_task_message(parsed_intents)
352
+ agent_result = await executor.run(task_message, initial_checkpoint=initial_checkpoint)
353
+
354
+ if not agent_result.success:
355
+ return {
356
+ "success": False,
357
+ "error": agent_result.error,
358
+ "yaml_preview": "",
359
+ "manifest": None,
360
+ "schemas": {},
361
+ "constraints": {},
362
+ "regex_nodes": {},
363
+ "warnings": [],
364
+ "iterations": agent_result.iterations,
365
+ }
366
+
367
+ config = agent_result.config or {}
368
+ if not config:
369
+ config = self._try_parse_config_from_content(agent_result.content) or {}
370
+
371
+ if not config.get("schemas") and not config.get("constraints"):
372
+ return {
373
+ "success": False,
374
+ "error": "未能从脚本中解析出有效配置",
375
+ "yaml_preview": "",
376
+ "manifest": None,
377
+ "schemas": {},
378
+ "constraints": {},
379
+ "regex_nodes": {},
380
+ "warnings": [],
381
+ "iterations": agent_result.iterations,
382
+ }
383
+
384
+ config["success"] = True
385
+ config["iterations"] = agent_result.iterations
386
+ config["warnings"] = config.get("warnings", [])
387
+ return config
388
+
389
+ async def _generate_for_chunk(
390
+ self,
391
+ instructions: str,
392
+ previous_config: dict[str, Any] | None,
393
+ ) -> dict[str, Any]:
394
+ """为单个分片生成配置,复用父类 _generate_config_for_scope。"""
395
+ return await self._generate_config_for_scope(
396
+ file_paths=self._file_paths,
397
+ instructions=instructions,
398
+ previous_config=previous_config,
399
+ scope={"file_paths": self._file_paths},
400
+ )
401
+
402
+ def _build_chunk_task_instructions(
403
+ self,
404
+ chunk_intents: list[dict[str, Any]],
405
+ chunk_total: int,
406
+ chunk_index: int,
407
+ ) -> str:
408
+ """构建分片生成指令。"""
409
+ intent_sections = []
410
+ for item in chunk_intents:
411
+ intent_sections.append(f"### 来源: {item['name']} ({item['language']})\n{item['intent']}")
412
+ intents_text = "\n\n".join(intent_sections)
413
+
414
+ parts = [
415
+ f"这是第 {chunk_index}/{chunk_total} 个分片,请仅基于本分片包含的来源意图生成配置。",
416
+ "",
417
+ "## 本分片已解析的迁移意图",
418
+ intents_text,
419
+ "",
420
+ "## 数据画像(全量上下文可见)",
421
+ self._format_profiling_for_agent(),
422
+ "",
423
+ "## 要求",
424
+ "- 仅生成本分片来源涉及的表、列、约束和正则",
425
+ "- 保持与数据画像一致",
426
+ "- 返回完整 JSON 配置(schemas、constraints、regex_nodes)",
427
+ ]
428
+ return "\n".join(parts)
429
+
430
+ async def _optional_refine_via_agent(
431
+ self,
432
+ config: dict[str, Any],
433
+ registry: ToolRegistry,
434
+ merge_warnings: list[str],
435
+ max_iterations: int,
436
+ max_tokens: int,
437
+ progress_callback: Callable[..., Any] | None,
438
+ checkpoint_callback: Callable[..., Any] | None,
439
+ ) -> dict[str, Any]:
440
+ """多分片合并后,通过 Agent 做校验 + 精修兜底。"""
441
+ provider = self._get_provider()
442
+ executor = AgentExecutor(
443
+ provider=provider,
444
+ registry=registry,
445
+ system_prompt=self._build_migrate_system_prompt(),
446
+ max_iterations=max_iterations,
447
+ max_tokens=max_tokens,
448
+ progress_callback=lambda stage, progress, extra: (
449
+ progress_callback(stage, 0.9 + progress * 0.05, extra) if progress_callback else None
450
+ ),
451
+ checkpoint_callback=checkpoint_callback,
452
+ cancelled_callback=lambda: self._cancelled,
453
+ )
454
+
455
+ parts = [
456
+ "以下配置由多个来源分片分别生成后合并而来,请做最终校验与精修。",
457
+ "",
458
+ "## 合并后配置",
459
+ self._summarize_config(config),
460
+ "",
461
+ "## 合并阶段警告",
462
+ "\n".join(merge_warnings) if merge_warnings else "无",
463
+ "",
464
+ "## 要求",
465
+ "- 检查跨来源冲突、重复约束、遗漏规则",
466
+ "- 调用 validate_config 校验",
467
+ "- 必要时调用 refine_config 修正",
468
+ "- 最终调用 generate_config 输出完整配置",
469
+ ]
470
+ task_message = "\n".join(parts)
471
+ agent_result = await executor.run(task_message)
472
+
473
+ if agent_result.success and agent_result.config:
474
+ refined = agent_result.config
475
+ # Agent 直接输出 JSON 时 schemas 可能是 list,需要归一化为 build_config 格式
476
+ if isinstance(refined.get("schemas"), list):
477
+ refined = self._build_config_from_llm_result(refined)
478
+ return refined
479
+
480
+ # 精修失败或没有输出时,回退到合并结果
481
+ return config
482
+
483
+ def _create_migrate_registry(self, validation_sample_size: int) -> ToolRegistry:
484
+ """创建迁移工具注册表。"""
485
+ registry = ToolRegistry()
486
+
487
+ # 工具注册统一走 register_tool(name/description/parameters/handler 自动提取)
488
+ registry.register_tool(
489
+ PlanChunksTool(
490
+ profiling_data=self._profiling_data,
491
+ file_paths=self._file_paths,
492
+ chunk_max_columns=20,
493
+ chunk_max_files=5,
494
+ )
495
+ )
496
+ registry.register_tool(MergeResultsTool())
497
+ registry.register_tool(ScriptParseTool(self))
498
+ registry.register_tool(ConfigGenerateTool(self))
499
+ registry.register_tool(
500
+ ConfigValidateTool(
501
+ file_paths=self._file_paths,
502
+ profiling_data=self._profiling_data,
503
+ sample_size=validation_sample_size,
504
+ )
505
+ )
506
+ registry.register_tool(ConfigRefineTool(self))
507
+
508
+ return registry
509
+
510
+ def _build_migrate_system_prompt(self) -> str:
511
+ """构建迁移系统提示词。"""
512
+ return """你是一个数据治理专家 Agent,擅长从旧脚本或业务描述中迁移生成 Precis V2 数据验证配置。
513
+
514
+ 可用工具:
515
+ 1. plan_chunks: 根据数据画像生成分块计划(大数据量时先调用)。
516
+ 2. merge_results: 合并多个分片生成的配置(分块生成后使用)。
517
+ 3. parse_script: 解析旧脚本或自然语言描述,输出规则意图。
518
+ 4. generate_config: 根据数据画像和规则意图生成配置。这是最终输出工具,调用后任务即结束。
519
+ 5. validate_config: 校验生成的配置。
520
+ 6. refine_config: 根据校验问题修正配置。
521
+
522
+ 工作原则:
523
+ - 当来源数量少时,直接综合调用 generate_config 生成统一配置。
524
+ - 当来源数量大时,服务层已按源拆分为多个分片分别生成并合并;你的职责是校验合并结果、处理冲突并精修。
525
+ - 如多个来源对同一表/列定义冲突,以数据画像为准并保留所有不冲突规则。
526
+ - 生成后校验并精修。
527
+ - 最终返回完整 JSON 配置。"""
528
+
529
+ def _build_migrate_task_message(self, parsed_intents: list[dict[str, Any]]) -> str:
530
+ """构建迁移任务消息。"""
531
+ intent_sections = []
532
+ for item in parsed_intents:
533
+ intent_sections.append(f"### 来源: {item['name']} ({item['language']})\n{item['intent']}")
534
+ intents_text = "\n\n".join(intent_sections)
535
+
536
+ parts = [
537
+ "从以下旧脚本/描述来源迁移生成 Precis V2 数据验证配置。",
538
+ "",
539
+ "## 已解析的迁移意图",
540
+ intents_text,
541
+ "",
542
+ "## 数据画像",
543
+ self._format_profiling_for_agent(),
544
+ "",
545
+ "## 要求",
546
+ "- 综合所有来源意图,生成统一、无冲突的完整配置",
547
+ "- 校验并精修",
548
+ "- 最终返回完整 JSON 配置",
549
+ ]
550
+ return "\n".join(parts)
@@ -0,0 +1,65 @@
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 AI 流式内核模块
17
+
18
+ 聚合导出流式事件层:EventJournal(持久化续传)、事件类型常量。
19
+ StreamingOrchestrator(包装 service 为事件流)与 SSE 响应封装在后续 task 添加。
20
+ """
21
+
22
+ from .event_journal import EventJournal
23
+ from .orchestrator import StreamingOrchestrator
24
+ from .sse_response import format_sse_event, sse_event_stream
25
+ from .types import (
26
+ EVENT_APPLY_CONFIRMED,
27
+ EVENT_APPLY_PENDING,
28
+ EVENT_APPLY_REJECTED,
29
+ EVENT_CANCELLED,
30
+ EVENT_COMPLETED,
31
+ EVENT_DELTA,
32
+ EVENT_ERROR,
33
+ EVENT_FRONTEND_INSTRUCTION,
34
+ EVENT_PROGRESS,
35
+ EVENT_STARTED,
36
+ EVENT_TOOL_CALL,
37
+ EVENT_TOOL_RESULT,
38
+ EVENT_TURN_START,
39
+ EVENT_USER_INPUT_REQUESTED,
40
+ EVENT_USER_RESPONDED,
41
+ TERMINAL_EVENTS,
42
+ )
43
+
44
+ __all__ = [
45
+ "EventJournal",
46
+ "StreamingOrchestrator",
47
+ "format_sse_event",
48
+ "sse_event_stream",
49
+ "EVENT_STARTED",
50
+ "EVENT_PROGRESS",
51
+ "EVENT_TURN_START",
52
+ "EVENT_DELTA",
53
+ "EVENT_TOOL_CALL",
54
+ "EVENT_TOOL_RESULT",
55
+ "EVENT_FRONTEND_INSTRUCTION",
56
+ "EVENT_APPLY_PENDING",
57
+ "EVENT_APPLY_CONFIRMED",
58
+ "EVENT_APPLY_REJECTED",
59
+ "EVENT_COMPLETED",
60
+ "EVENT_ERROR",
61
+ "EVENT_CANCELLED",
62
+ "EVENT_USER_INPUT_REQUESTED",
63
+ "EVENT_USER_RESPONDED",
64
+ "TERMINAL_EVENTS",
65
+ ]