auto-coder 0.1.400__py3-none-any.whl → 2.0.0__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.

Potentially problematic release.


This version of auto-coder might be problematic. Click here for more details.

Files changed (579) hide show
  1. auto_coder-2.0.0.dist-info/LICENSE +158 -0
  2. auto_coder-2.0.0.dist-info/METADATA +558 -0
  3. auto_coder-2.0.0.dist-info/RECORD +795 -0
  4. {auto_coder-0.1.400.dist-info → auto_coder-2.0.0.dist-info}/WHEEL +1 -1
  5. {auto_coder-0.1.400.dist-info → auto_coder-2.0.0.dist-info}/entry_points.txt +3 -3
  6. autocoder/__init__.py +31 -0
  7. autocoder/agent/auto_filegroup.py +32 -13
  8. autocoder/agent/auto_learn_from_commit.py +9 -1
  9. autocoder/agent/base_agentic/__init__.py +3 -0
  10. autocoder/agent/base_agentic/agent_hub.py +1 -1
  11. autocoder/agent/base_agentic/base_agent.py +235 -136
  12. autocoder/agent/base_agentic/default_tools.py +119 -118
  13. autocoder/agent/base_agentic/test_base_agent.py +1 -1
  14. autocoder/agent/base_agentic/tool_registry.py +32 -20
  15. autocoder/agent/base_agentic/tools/read_file_tool_resolver.py +25 -4
  16. autocoder/agent/base_agentic/tools/write_to_file_tool_resolver.py +24 -11
  17. autocoder/agent/base_agentic/types.py +42 -0
  18. autocoder/agent/entry_command_agent/chat.py +73 -59
  19. autocoder/auto_coder.py +31 -40
  20. autocoder/auto_coder_rag.py +11 -1084
  21. autocoder/auto_coder_runner.py +1029 -2310
  22. autocoder/auto_coder_terminal.py +26 -0
  23. autocoder/auto_coder_terminal_v3.py +190 -0
  24. autocoder/chat/conf_command.py +224 -124
  25. autocoder/chat/models_command.py +361 -299
  26. autocoder/chat/rules_command.py +79 -31
  27. autocoder/chat_auto_coder.py +1021 -372
  28. autocoder/chat_auto_coder_lang.py +23 -732
  29. autocoder/commands/auto_command.py +26 -9
  30. autocoder/commands/auto_web.py +1 -1
  31. autocoder/commands/tools.py +44 -44
  32. autocoder/common/__init__.py +150 -128
  33. autocoder/common/ac_style_command_parser/__init__.py +39 -2
  34. autocoder/common/ac_style_command_parser/config.py +422 -0
  35. autocoder/common/ac_style_command_parser/parser.py +292 -78
  36. autocoder/common/ac_style_command_parser/test_parser.py +241 -16
  37. autocoder/common/ac_style_command_parser/test_typed_parser.py +342 -0
  38. autocoder/common/ac_style_command_parser/typed_parser.py +653 -0
  39. autocoder/common/action_yml_file_manager.py +25 -13
  40. autocoder/common/agent_events/__init__.py +52 -0
  41. autocoder/common/agent_events/agent_event_emitter.py +193 -0
  42. autocoder/common/agent_events/event_factory.py +177 -0
  43. autocoder/common/agent_events/examples.py +307 -0
  44. autocoder/common/agent_events/types.py +113 -0
  45. autocoder/common/agent_events/utils.py +68 -0
  46. autocoder/common/agent_hooks/__init__.py +44 -0
  47. autocoder/common/agent_hooks/examples.py +582 -0
  48. autocoder/common/agent_hooks/hook_executor.py +217 -0
  49. autocoder/common/agent_hooks/hook_manager.py +288 -0
  50. autocoder/common/agent_hooks/types.py +133 -0
  51. autocoder/common/agent_hooks/utils.py +99 -0
  52. autocoder/common/agent_query_queue/queue_executor.py +324 -0
  53. autocoder/common/agent_query_queue/queue_manager.py +325 -0
  54. autocoder/common/agents/__init__.py +11 -0
  55. autocoder/common/agents/agent_manager.py +323 -0
  56. autocoder/common/agents/agent_parser.py +189 -0
  57. autocoder/common/agents/example_usage.py +344 -0
  58. autocoder/common/agents/integration_example.py +330 -0
  59. autocoder/common/agents/test_agent_parser.py +545 -0
  60. autocoder/common/async_utils.py +101 -0
  61. autocoder/common/auto_coder_lang.py +23 -972
  62. autocoder/common/autocoderargs_parser/__init__.py +14 -0
  63. autocoder/common/autocoderargs_parser/parser.py +184 -0
  64. autocoder/common/autocoderargs_parser/tests/__init__.py +1 -0
  65. autocoder/common/autocoderargs_parser/tests/test_args_parser.py +235 -0
  66. autocoder/common/autocoderargs_parser/tests/test_token_parser.py +195 -0
  67. autocoder/common/autocoderargs_parser/token_parser.py +290 -0
  68. autocoder/common/buildin_tokenizer.py +2 -4
  69. autocoder/common/code_auto_generate.py +149 -74
  70. autocoder/common/code_auto_generate_diff.py +163 -70
  71. autocoder/common/code_auto_generate_editblock.py +179 -89
  72. autocoder/common/code_auto_generate_strict_diff.py +167 -72
  73. autocoder/common/code_auto_merge_editblock.py +13 -6
  74. autocoder/common/code_modification_ranker.py +1 -1
  75. autocoder/common/command_completer.py +3 -3
  76. autocoder/common/command_file_manager/manager.py +183 -47
  77. autocoder/common/command_file_manager/test_command_file_manager.py +507 -0
  78. autocoder/common/command_templates.py +1 -1
  79. autocoder/common/conf_utils.py +2 -4
  80. autocoder/common/conversations/config.py +11 -3
  81. autocoder/common/conversations/get_conversation_manager.py +100 -2
  82. autocoder/common/conversations/llm_stats_models.py +264 -0
  83. autocoder/common/conversations/manager.py +112 -28
  84. autocoder/common/conversations/models.py +16 -2
  85. autocoder/common/conversations/storage/index_manager.py +134 -10
  86. autocoder/common/core_config/__init__.py +63 -0
  87. autocoder/common/core_config/agentic_mode_manager.py +109 -0
  88. autocoder/common/core_config/base_manager.py +123 -0
  89. autocoder/common/core_config/compatibility.py +151 -0
  90. autocoder/common/core_config/config_manager.py +156 -0
  91. autocoder/common/core_config/conversation_manager.py +31 -0
  92. autocoder/common/core_config/exclude_manager.py +72 -0
  93. autocoder/common/core_config/file_manager.py +177 -0
  94. autocoder/common/core_config/human_as_model_manager.py +129 -0
  95. autocoder/common/core_config/lib_manager.py +54 -0
  96. autocoder/common/core_config/main_manager.py +81 -0
  97. autocoder/common/core_config/mode_manager.py +126 -0
  98. autocoder/common/core_config/models.py +70 -0
  99. autocoder/common/core_config/test_memory_manager.py +1056 -0
  100. autocoder/common/env_manager.py +282 -0
  101. autocoder/common/env_manager_usage_example.py +211 -0
  102. autocoder/common/file_checkpoint/conversation_checkpoint.py +19 -19
  103. autocoder/common/file_checkpoint/manager.py +264 -48
  104. autocoder/common/file_checkpoint/test_backup.py +1 -18
  105. autocoder/common/file_checkpoint/test_manager.py +270 -1
  106. autocoder/common/file_checkpoint/test_store.py +1 -17
  107. autocoder/common/file_handler/__init__.py +23 -0
  108. autocoder/common/file_handler/active_context_handler.py +159 -0
  109. autocoder/common/file_handler/add_files_handler.py +409 -0
  110. autocoder/common/file_handler/chat_handler.py +180 -0
  111. autocoder/common/file_handler/coding_handler.py +401 -0
  112. autocoder/common/file_handler/commit_handler.py +200 -0
  113. autocoder/common/file_handler/lib_handler.py +156 -0
  114. autocoder/common/file_handler/list_files_handler.py +111 -0
  115. autocoder/common/file_handler/mcp_handler.py +268 -0
  116. autocoder/common/file_handler/models_handler.py +493 -0
  117. autocoder/common/file_handler/remove_files_handler.py +172 -0
  118. autocoder/common/file_monitor/test_file_monitor.py +307 -0
  119. autocoder/common/git_utils.py +51 -10
  120. autocoder/common/global_cancel.py +15 -6
  121. autocoder/common/ignorefiles/test_ignore_file_utils.py +1 -1
  122. autocoder/common/international/__init__.py +31 -0
  123. autocoder/common/international/demo_international.py +92 -0
  124. autocoder/common/international/message_manager.py +157 -0
  125. autocoder/common/international/messages/__init__.py +56 -0
  126. autocoder/common/international/messages/async_command_messages.py +507 -0
  127. autocoder/common/international/messages/auto_coder_messages.py +2208 -0
  128. autocoder/common/international/messages/chat_auto_coder_messages.py +1547 -0
  129. autocoder/common/international/messages/command_help_messages.py +986 -0
  130. autocoder/common/international/messages/conversation_command_messages.py +191 -0
  131. autocoder/common/international/messages/git_helper_plugin_messages.py +159 -0
  132. autocoder/common/international/messages/queue_command_messages.py +751 -0
  133. autocoder/common/international/messages/rules_command_messages.py +77 -0
  134. autocoder/common/international/messages/sdk_messages.py +1707 -0
  135. autocoder/common/international/messages/token_helper_plugin_messages.py +361 -0
  136. autocoder/common/international/messages/tool_display_messages.py +1212 -0
  137. autocoder/common/international/messages/workflow_exception_messages.py +473 -0
  138. autocoder/common/international/test_international.py +612 -0
  139. autocoder/common/linter_core/__init__.py +28 -0
  140. autocoder/common/linter_core/base_linter.py +61 -0
  141. autocoder/common/linter_core/config_loader.py +271 -0
  142. autocoder/common/linter_core/formatters/__init__.py +0 -0
  143. autocoder/common/linter_core/formatters/base_formatter.py +38 -0
  144. autocoder/common/linter_core/formatters/raw_formatter.py +17 -0
  145. autocoder/common/linter_core/linter.py +166 -0
  146. autocoder/common/linter_core/linter_factory.py +216 -0
  147. autocoder/common/linter_core/linter_manager.py +333 -0
  148. autocoder/common/linter_core/linters/__init__.py +9 -0
  149. autocoder/common/linter_core/linters/java_linter.py +342 -0
  150. autocoder/common/linter_core/linters/python_linter.py +115 -0
  151. autocoder/common/linter_core/linters/typescript_linter.py +119 -0
  152. autocoder/common/linter_core/models/__init__.py +7 -0
  153. autocoder/common/linter_core/models/lint_result.py +91 -0
  154. autocoder/common/linter_core/models.py +33 -0
  155. autocoder/common/linter_core/tests/__init__.py +3 -0
  156. autocoder/common/linter_core/tests/test_config_loader.py +323 -0
  157. autocoder/common/linter_core/tests/test_config_loading.py +308 -0
  158. autocoder/common/linter_core/tests/test_factory_manager.py +234 -0
  159. autocoder/common/linter_core/tests/test_formatters.py +147 -0
  160. autocoder/common/linter_core/tests/test_integration.py +317 -0
  161. autocoder/common/linter_core/tests/test_java_linter.py +496 -0
  162. autocoder/common/linter_core/tests/test_linters.py +265 -0
  163. autocoder/common/linter_core/tests/test_models.py +81 -0
  164. autocoder/common/linter_core/tests/verify_config_loading.py +296 -0
  165. autocoder/common/linter_core/tests/verify_fixes.py +183 -0
  166. autocoder/common/llm_friendly_package/__init__.py +31 -0
  167. autocoder/common/llm_friendly_package/base_manager.py +102 -0
  168. autocoder/common/llm_friendly_package/docs_manager.py +121 -0
  169. autocoder/common/llm_friendly_package/library_manager.py +171 -0
  170. autocoder/common/{llm_friendly_package.py → llm_friendly_package/main_manager.py} +204 -231
  171. autocoder/common/llm_friendly_package/models.py +40 -0
  172. autocoder/common/llm_friendly_package/test_llm_friendly_package.py +536 -0
  173. autocoder/common/llms/__init__.py +15 -0
  174. autocoder/common/llms/demo_error_handling.py +85 -0
  175. autocoder/common/llms/factory.py +142 -0
  176. autocoder/common/llms/manager.py +264 -0
  177. autocoder/common/llms/pricing.py +121 -0
  178. autocoder/common/llms/registry.py +288 -0
  179. autocoder/common/llms/schema.py +77 -0
  180. autocoder/common/llms/simple_demo.py +45 -0
  181. autocoder/common/llms/test_quick_model.py +116 -0
  182. autocoder/common/llms/test_remove_functionality.py +182 -0
  183. autocoder/common/llms/tests/__init__.py +1 -0
  184. autocoder/common/llms/tests/test_manager.py +330 -0
  185. autocoder/common/llms/tests/test_registry.py +364 -0
  186. autocoder/common/mcp_tools/__init__.py +62 -0
  187. autocoder/common/{mcp_tools.py → mcp_tools/executor.py} +49 -40
  188. autocoder/common/{mcp_hub.py → mcp_tools/hub.py} +42 -68
  189. autocoder/common/{mcp_server_install.py → mcp_tools/installer.py} +16 -28
  190. autocoder/common/{mcp_server.py → mcp_tools/server.py} +176 -48
  191. autocoder/common/mcp_tools/test_keyboard_interrupt.py +93 -0
  192. autocoder/common/mcp_tools/test_mcp_tools.py +391 -0
  193. autocoder/common/{mcp_server_types.py → mcp_tools/types.py} +121 -48
  194. autocoder/common/mcp_tools/verify_functionality.py +202 -0
  195. autocoder/common/model_speed_tester.py +32 -26
  196. autocoder/common/priority_directory_finder/__init__.py +142 -0
  197. autocoder/common/priority_directory_finder/examples.py +230 -0
  198. autocoder/common/priority_directory_finder/finder.py +283 -0
  199. autocoder/common/priority_directory_finder/models.py +236 -0
  200. autocoder/common/priority_directory_finder/test_priority_directory_finder.py +431 -0
  201. autocoder/common/project_scanner/__init__.py +18 -0
  202. autocoder/common/project_scanner/compat.py +77 -0
  203. autocoder/common/project_scanner/scanner.py +436 -0
  204. autocoder/common/project_tracker/__init__.py +27 -0
  205. autocoder/common/project_tracker/api.py +228 -0
  206. autocoder/common/project_tracker/demo.py +272 -0
  207. autocoder/common/project_tracker/tracker.py +487 -0
  208. autocoder/common/project_tracker/types.py +53 -0
  209. autocoder/common/pruner/__init__.py +67 -0
  210. autocoder/common/pruner/agentic_conversation_pruner.py +746 -0
  211. autocoder/common/{context_pruner.py → pruner/context_pruner.py} +137 -40
  212. autocoder/common/pruner/conversation_message_ids_api.py +386 -0
  213. autocoder/common/pruner/conversation_message_ids_manager.py +347 -0
  214. autocoder/common/pruner/conversation_message_ids_pruner.py +473 -0
  215. autocoder/common/pruner/conversation_normalizer.py +347 -0
  216. autocoder/common/{conversation_pruner.py → pruner/conversation_pruner.py} +26 -6
  217. autocoder/common/pruner/test_agentic_conversation_pruner.py +784 -0
  218. autocoder/common/pruner/test_context_pruner.py +546 -0
  219. autocoder/common/pruner/test_conversation_normalizer.py +502 -0
  220. autocoder/common/pruner/test_tool_content_detector.py +324 -0
  221. autocoder/common/pruner/tool_content_detector.py +227 -0
  222. autocoder/common/pruner/tools/__init__.py +18 -0
  223. autocoder/common/pruner/tools/query_message_ids.py +264 -0
  224. autocoder/common/pruner/tools/test_agentic_pruning_logic.py +432 -0
  225. autocoder/common/pruner/tools/test_message_ids_pruning_only.py +192 -0
  226. autocoder/common/pull_requests/__init__.py +9 -1
  227. autocoder/common/pull_requests/utils.py +122 -1
  228. autocoder/common/rag_manager/rag_manager.py +36 -40
  229. autocoder/common/rulefiles/__init__.py +53 -1
  230. autocoder/common/rulefiles/api.py +250 -0
  231. autocoder/common/rulefiles/core/__init__.py +14 -0
  232. autocoder/common/rulefiles/core/manager.py +241 -0
  233. autocoder/common/rulefiles/core/selector.py +805 -0
  234. autocoder/common/rulefiles/models/__init__.py +20 -0
  235. autocoder/common/rulefiles/models/index.py +16 -0
  236. autocoder/common/rulefiles/models/init_rule.py +18 -0
  237. autocoder/common/rulefiles/models/rule_file.py +18 -0
  238. autocoder/common/rulefiles/models/rule_relevance.py +14 -0
  239. autocoder/common/rulefiles/models/summary.py +16 -0
  240. autocoder/common/rulefiles/test_rulefiles.py +776 -0
  241. autocoder/common/rulefiles/utils/__init__.py +34 -0
  242. autocoder/common/rulefiles/utils/monitor.py +86 -0
  243. autocoder/common/rulefiles/utils/parser.py +230 -0
  244. autocoder/common/save_formatted_log.py +67 -10
  245. autocoder/common/search_replace.py +8 -1
  246. autocoder/common/search_replace_patch/__init__.py +24 -0
  247. autocoder/common/search_replace_patch/base.py +115 -0
  248. autocoder/common/search_replace_patch/manager.py +248 -0
  249. autocoder/common/search_replace_patch/patch_replacer.py +304 -0
  250. autocoder/common/search_replace_patch/similarity_replacer.py +306 -0
  251. autocoder/common/search_replace_patch/string_replacer.py +181 -0
  252. autocoder/common/search_replace_patch/tests/__init__.py +3 -0
  253. autocoder/common/search_replace_patch/tests/run_tests.py +126 -0
  254. autocoder/common/search_replace_patch/tests/test_base.py +188 -0
  255. autocoder/common/search_replace_patch/tests/test_empty_line_insert.py +233 -0
  256. autocoder/common/search_replace_patch/tests/test_integration.py +389 -0
  257. autocoder/common/search_replace_patch/tests/test_manager.py +351 -0
  258. autocoder/common/search_replace_patch/tests/test_patch_replacer.py +316 -0
  259. autocoder/common/search_replace_patch/tests/test_regex_replacer.py +306 -0
  260. autocoder/common/search_replace_patch/tests/test_similarity_replacer.py +384 -0
  261. autocoder/common/shell_commands/__init__.py +197 -0
  262. autocoder/common/shell_commands/background_process_notifier.py +346 -0
  263. autocoder/common/shell_commands/command_executor.py +1127 -0
  264. autocoder/common/shell_commands/error_recovery.py +541 -0
  265. autocoder/common/shell_commands/exceptions.py +120 -0
  266. autocoder/common/shell_commands/interactive_executor.py +476 -0
  267. autocoder/common/shell_commands/interactive_pexpect_process.py +623 -0
  268. autocoder/common/shell_commands/interactive_process.py +744 -0
  269. autocoder/common/shell_commands/interactive_session_manager.py +1014 -0
  270. autocoder/common/shell_commands/monitoring.py +529 -0
  271. autocoder/common/shell_commands/process_cleanup.py +386 -0
  272. autocoder/common/shell_commands/process_manager.py +606 -0
  273. autocoder/common/shell_commands/test_interactive_pexpect_process.py +281 -0
  274. autocoder/common/shell_commands/tests/__init__.py +6 -0
  275. autocoder/common/shell_commands/tests/conftest.py +118 -0
  276. autocoder/common/shell_commands/tests/test_background_process_notifier.py +703 -0
  277. autocoder/common/shell_commands/tests/test_command_executor.py +448 -0
  278. autocoder/common/shell_commands/tests/test_error_recovery.py +305 -0
  279. autocoder/common/shell_commands/tests/test_exceptions.py +299 -0
  280. autocoder/common/shell_commands/tests/test_execute_batch.py +588 -0
  281. autocoder/common/shell_commands/tests/test_indented_batch_commands.py +244 -0
  282. autocoder/common/shell_commands/tests/test_integration.py +664 -0
  283. autocoder/common/shell_commands/tests/test_monitoring.py +546 -0
  284. autocoder/common/shell_commands/tests/test_performance.py +632 -0
  285. autocoder/common/shell_commands/tests/test_process_cleanup.py +397 -0
  286. autocoder/common/shell_commands/tests/test_process_manager.py +606 -0
  287. autocoder/common/shell_commands/tests/test_timeout_config.py +343 -0
  288. autocoder/common/shell_commands/tests/test_timeout_manager.py +520 -0
  289. autocoder/common/shell_commands/timeout_config.py +315 -0
  290. autocoder/common/shell_commands/timeout_manager.py +352 -0
  291. autocoder/common/terminal_paste/__init__.py +14 -0
  292. autocoder/common/terminal_paste/demo.py +145 -0
  293. autocoder/common/terminal_paste/demo_paste_functionality.py +95 -0
  294. autocoder/common/terminal_paste/paste_handler.py +200 -0
  295. autocoder/common/terminal_paste/paste_manager.py +118 -0
  296. autocoder/common/terminal_paste/tests/__init__.py +1 -0
  297. autocoder/common/terminal_paste/tests/test_paste_handler.py +182 -0
  298. autocoder/common/terminal_paste/tests/test_paste_manager.py +126 -0
  299. autocoder/common/terminal_paste/utils.py +163 -0
  300. autocoder/common/test_autocoder_args.py +232 -0
  301. autocoder/common/test_env_manager.py +173 -0
  302. autocoder/common/test_env_manager_integration.py +159 -0
  303. autocoder/common/text_similarity/__init__.py +9 -0
  304. autocoder/common/text_similarity/demo.py +216 -0
  305. autocoder/common/text_similarity/examples.py +266 -0
  306. autocoder/common/text_similarity/test_text_similarity.py +306 -0
  307. autocoder/common/text_similarity/text_similarity.py +194 -0
  308. autocoder/common/text_similarity/utils.py +125 -0
  309. autocoder/common/todos/__init__.py +61 -0
  310. autocoder/common/todos/cache/__init__.py +16 -0
  311. autocoder/common/todos/cache/base_cache.py +89 -0
  312. autocoder/common/todos/cache/cache_manager.py +228 -0
  313. autocoder/common/todos/cache/memory_cache.py +225 -0
  314. autocoder/common/todos/config.py +155 -0
  315. autocoder/common/todos/exceptions.py +35 -0
  316. autocoder/common/todos/get_todo_manager.py +161 -0
  317. autocoder/common/todos/manager.py +537 -0
  318. autocoder/common/todos/models.py +239 -0
  319. autocoder/common/todos/storage/__init__.py +14 -0
  320. autocoder/common/todos/storage/base_storage.py +76 -0
  321. autocoder/common/todos/storage/file_storage.py +278 -0
  322. autocoder/common/tokens/__init__.py +15 -0
  323. autocoder/common/tokens/counter.py +44 -2
  324. autocoder/common/tools_manager/__init__.py +17 -0
  325. autocoder/common/tools_manager/examples.py +162 -0
  326. autocoder/common/tools_manager/manager.py +385 -0
  327. autocoder/common/tools_manager/models.py +39 -0
  328. autocoder/common/tools_manager/test_tools_manager.py +303 -0
  329. autocoder/common/tools_manager/utils.py +191 -0
  330. autocoder/common/v2/agent/agentic_callbacks.py +270 -0
  331. autocoder/common/v2/agent/agentic_edit.py +2729 -2052
  332. autocoder/common/v2/agent/agentic_edit_change_manager.py +474 -0
  333. autocoder/common/v2/agent/agentic_edit_tools/__init__.py +43 -2
  334. autocoder/common/v2/agent/agentic_edit_tools/ac_mod_list_tool_resolver.py +279 -0
  335. autocoder/common/v2/agent/agentic_edit_tools/ac_mod_read_tool_resolver.py +40 -0
  336. autocoder/common/v2/agent/agentic_edit_tools/ac_mod_write_tool_resolver.py +52 -0
  337. autocoder/common/v2/agent/agentic_edit_tools/ask_followup_question_tool_resolver.py +8 -0
  338. autocoder/common/v2/agent/agentic_edit_tools/background_task_tool_resolver.py +1167 -0
  339. autocoder/common/v2/agent/agentic_edit_tools/base_tool_resolver.py +2 -2
  340. autocoder/common/v2/agent/agentic_edit_tools/conversation_message_ids_read_tool_resolver.py +214 -0
  341. autocoder/common/v2/agent/agentic_edit_tools/conversation_message_ids_write_tool_resolver.py +299 -0
  342. autocoder/common/v2/agent/agentic_edit_tools/count_tokens_tool_resolver.py +290 -0
  343. autocoder/common/v2/agent/agentic_edit_tools/execute_command_tool_resolver.py +565 -30
  344. autocoder/common/v2/agent/agentic_edit_tools/execute_workflow_tool_resolver.py +485 -0
  345. autocoder/common/v2/agent/agentic_edit_tools/extract_to_text_tool_resolver.py +225 -0
  346. autocoder/common/v2/agent/agentic_edit_tools/lint_report.py +79 -0
  347. autocoder/common/v2/agent/agentic_edit_tools/linter_config_models.py +343 -0
  348. autocoder/common/v2/agent/agentic_edit_tools/linter_enabled_tool_resolver.py +189 -0
  349. autocoder/common/v2/agent/agentic_edit_tools/list_files_tool_resolver.py +169 -101
  350. autocoder/common/v2/agent/agentic_edit_tools/load_extra_document_tool_resolver.py +349 -0
  351. autocoder/common/v2/agent/agentic_edit_tools/read_file_tool_resolver.py +244 -51
  352. autocoder/common/v2/agent/agentic_edit_tools/replace_in_file_tool_resolver.py +667 -147
  353. autocoder/common/v2/agent/agentic_edit_tools/run_named_subagents_tool_resolver.py +691 -0
  354. autocoder/common/v2/agent/agentic_edit_tools/search_files_tool_resolver.py +409 -140
  355. autocoder/common/v2/agent/agentic_edit_tools/session_interactive_tool_resolver.py +115 -0
  356. autocoder/common/v2/agent/agentic_edit_tools/session_start_tool_resolver.py +190 -0
  357. autocoder/common/v2/agent/agentic_edit_tools/session_stop_tool_resolver.py +76 -0
  358. autocoder/common/v2/agent/agentic_edit_tools/test_write_to_file_tool_resolver.py +209 -194
  359. autocoder/common/v2/agent/agentic_edit_tools/todo_read_tool_resolver.py +135 -0
  360. autocoder/common/v2/agent/agentic_edit_tools/todo_write_tool_resolver.py +328 -0
  361. autocoder/common/v2/agent/agentic_edit_tools/use_mcp_tool_resolver.py +2 -2
  362. autocoder/common/v2/agent/agentic_edit_tools/web_crawl_tool_resolver.py +557 -0
  363. autocoder/common/v2/agent/agentic_edit_tools/web_search_tool_resolver.py +600 -0
  364. autocoder/common/v2/agent/agentic_edit_tools/write_to_file_tool_resolver.py +56 -121
  365. autocoder/common/v2/agent/agentic_edit_types.py +386 -10
  366. autocoder/common/v2/agent/runner/__init__.py +31 -0
  367. autocoder/common/v2/agent/runner/base_runner.py +92 -0
  368. autocoder/common/v2/agent/runner/file_based_event_runner.py +217 -0
  369. autocoder/common/v2/agent/runner/sdk_runner.py +182 -0
  370. autocoder/common/v2/agent/runner/terminal_runner.py +396 -0
  371. autocoder/common/v2/agent/runner/tool_display.py +589 -0
  372. autocoder/common/v2/agent/test_agentic_callbacks.py +265 -0
  373. autocoder/common/v2/agent/test_agentic_edit.py +194 -0
  374. autocoder/common/v2/agent/tool_caller/__init__.py +24 -0
  375. autocoder/common/v2/agent/tool_caller/default_tool_resolver_map.py +135 -0
  376. autocoder/common/v2/agent/tool_caller/integration_test.py +172 -0
  377. autocoder/common/v2/agent/tool_caller/plugins/__init__.py +14 -0
  378. autocoder/common/v2/agent/tool_caller/plugins/base_plugin.py +126 -0
  379. autocoder/common/v2/agent/tool_caller/plugins/examples/__init__.py +13 -0
  380. autocoder/common/v2/agent/tool_caller/plugins/examples/logging_plugin.py +164 -0
  381. autocoder/common/v2/agent/tool_caller/plugins/examples/security_filter_plugin.py +198 -0
  382. autocoder/common/v2/agent/tool_caller/plugins/plugin_interface.py +141 -0
  383. autocoder/common/v2/agent/tool_caller/test_tool_caller.py +278 -0
  384. autocoder/common/v2/agent/tool_caller/tool_call_plugin_manager.py +331 -0
  385. autocoder/common/v2/agent/tool_caller/tool_caller.py +337 -0
  386. autocoder/common/v2/agent/tool_caller/usage_example.py +193 -0
  387. autocoder/common/v2/code_agentic_editblock_manager.py +4 -4
  388. autocoder/common/v2/code_auto_generate.py +136 -78
  389. autocoder/common/v2/code_auto_generate_diff.py +135 -79
  390. autocoder/common/v2/code_auto_generate_editblock.py +174 -99
  391. autocoder/common/v2/code_auto_generate_strict_diff.py +151 -71
  392. autocoder/common/v2/code_auto_merge.py +1 -1
  393. autocoder/common/v2/code_auto_merge_editblock.py +13 -1
  394. autocoder/common/v2/code_diff_manager.py +3 -3
  395. autocoder/common/v2/code_editblock_manager.py +4 -14
  396. autocoder/common/v2/code_manager.py +1 -1
  397. autocoder/common/v2/code_strict_diff_manager.py +2 -2
  398. autocoder/common/wrap_llm_hint/__init__.py +10 -0
  399. autocoder/common/wrap_llm_hint/test_wrap_llm_hint.py +1067 -0
  400. autocoder/common/wrap_llm_hint/utils.py +432 -0
  401. autocoder/common/wrap_llm_hint/wrap_llm_hint.py +323 -0
  402. autocoder/completer/__init__.py +8 -0
  403. autocoder/completer/command_completer_v2.py +1051 -0
  404. autocoder/default_project/__init__.py +501 -0
  405. autocoder/dispacher/__init__.py +4 -12
  406. autocoder/dispacher/actions/action.py +165 -7
  407. autocoder/dispacher/actions/plugins/action_regex_project.py +2 -2
  408. autocoder/index/entry.py +117 -125
  409. autocoder/{agent → index/filter}/agentic_filter.py +323 -334
  410. autocoder/index/filter/normal_filter.py +5 -11
  411. autocoder/index/filter/quick_filter.py +1 -1
  412. autocoder/index/index.py +36 -9
  413. autocoder/index/tests/__init__.py +1 -0
  414. autocoder/index/tests/run_tests.py +195 -0
  415. autocoder/index/tests/test_entry.py +303 -0
  416. autocoder/index/tests/test_index_manager.py +314 -0
  417. autocoder/index/tests/test_module_integration.py +300 -0
  418. autocoder/index/tests/test_symbols_utils.py +183 -0
  419. autocoder/inner/__init__.py +4 -0
  420. autocoder/inner/agentic.py +932 -0
  421. autocoder/inner/async_command_handler.py +992 -0
  422. autocoder/inner/conversation_command_handlers.py +623 -0
  423. autocoder/inner/merge_command_handler.py +213 -0
  424. autocoder/inner/queue_command_handler.py +684 -0
  425. autocoder/models.py +95 -266
  426. autocoder/plugins/git_helper_plugin.py +31 -29
  427. autocoder/plugins/token_helper_plugin.py +156 -37
  428. autocoder/pyproject/__init__.py +32 -29
  429. autocoder/rag/agentic_rag.py +215 -75
  430. autocoder/rag/cache/simple_cache.py +1 -2
  431. autocoder/rag/loaders/image_loader.py +1 -1
  432. autocoder/rag/long_context_rag.py +42 -26
  433. autocoder/rag/qa_conversation_strategy.py +1 -1
  434. autocoder/rag/terminal/__init__.py +17 -0
  435. autocoder/rag/terminal/args.py +581 -0
  436. autocoder/rag/terminal/bootstrap.py +61 -0
  437. autocoder/rag/terminal/command_handlers.py +653 -0
  438. autocoder/rag/terminal/formatters/__init__.py +20 -0
  439. autocoder/rag/terminal/formatters/base.py +70 -0
  440. autocoder/rag/terminal/formatters/json_format.py +66 -0
  441. autocoder/rag/terminal/formatters/stream_json.py +95 -0
  442. autocoder/rag/terminal/formatters/text.py +28 -0
  443. autocoder/rag/terminal/init.py +120 -0
  444. autocoder/rag/terminal/utils.py +106 -0
  445. autocoder/rag/test_agentic_rag.py +389 -0
  446. autocoder/rag/test_doc_filter.py +3 -3
  447. autocoder/rag/test_long_context_rag.py +1 -1
  448. autocoder/rag/test_token_limiter.py +517 -10
  449. autocoder/rag/token_counter.py +3 -0
  450. autocoder/rag/token_limiter.py +19 -15
  451. autocoder/rag/tools/__init__.py +26 -2
  452. autocoder/rag/tools/bochaai_example.py +343 -0
  453. autocoder/rag/tools/bochaai_sdk.py +541 -0
  454. autocoder/rag/tools/metaso_example.py +268 -0
  455. autocoder/rag/tools/metaso_sdk.py +417 -0
  456. autocoder/rag/tools/recall_tool.py +28 -7
  457. autocoder/rag/tools/run_integration_tests.py +204 -0
  458. autocoder/rag/tools/test_all_providers.py +318 -0
  459. autocoder/rag/tools/test_bochaai_integration.py +482 -0
  460. autocoder/rag/tools/test_final_integration.py +215 -0
  461. autocoder/rag/tools/test_metaso_integration.py +424 -0
  462. autocoder/rag/tools/test_metaso_real.py +171 -0
  463. autocoder/rag/tools/test_web_crawl_tool.py +639 -0
  464. autocoder/rag/tools/test_web_search_tool.py +509 -0
  465. autocoder/rag/tools/todo_read_tool.py +202 -0
  466. autocoder/rag/tools/todo_write_tool.py +412 -0
  467. autocoder/rag/tools/web_crawl_tool.py +634 -0
  468. autocoder/rag/tools/web_search_tool.py +558 -0
  469. autocoder/rag/tools/web_tools_example.py +119 -0
  470. autocoder/rag/types.py +16 -0
  471. autocoder/rag/variable_holder.py +4 -2
  472. autocoder/rags.py +86 -79
  473. autocoder/regexproject/__init__.py +23 -21
  474. autocoder/run_context.py +9 -0
  475. autocoder/sdk/__init__.py +50 -161
  476. autocoder/sdk/api.py +370 -0
  477. autocoder/sdk/async_runner/__init__.py +26 -0
  478. autocoder/sdk/async_runner/async_executor.py +650 -0
  479. autocoder/sdk/async_runner/async_handler.py +356 -0
  480. autocoder/sdk/async_runner/markdown_processor.py +595 -0
  481. autocoder/sdk/async_runner/task_metadata.py +284 -0
  482. autocoder/sdk/async_runner/worktree_manager.py +438 -0
  483. autocoder/sdk/cli/__init__.py +2 -5
  484. autocoder/sdk/cli/formatters.py +28 -204
  485. autocoder/sdk/cli/handlers.py +77 -44
  486. autocoder/sdk/cli/main.py +158 -170
  487. autocoder/sdk/cli/options.py +95 -22
  488. autocoder/sdk/constants.py +139 -51
  489. autocoder/sdk/core/auto_coder_core.py +484 -267
  490. autocoder/sdk/core/bridge.py +298 -118
  491. autocoder/sdk/exceptions.py +18 -12
  492. autocoder/sdk/formatters/__init__.py +19 -0
  493. autocoder/sdk/formatters/input.py +64 -0
  494. autocoder/sdk/formatters/output.py +247 -0
  495. autocoder/sdk/formatters/stream.py +54 -0
  496. autocoder/sdk/models/__init__.py +6 -5
  497. autocoder/sdk/models/options.py +55 -18
  498. autocoder/sdk/utils/formatters.py +27 -195
  499. autocoder/suffixproject/__init__.py +28 -25
  500. autocoder/terminal/__init__.py +14 -0
  501. autocoder/terminal/app.py +454 -0
  502. autocoder/terminal/args.py +32 -0
  503. autocoder/terminal/bootstrap.py +178 -0
  504. autocoder/terminal/command_processor.py +521 -0
  505. autocoder/terminal/command_registry.py +57 -0
  506. autocoder/terminal/help.py +97 -0
  507. autocoder/terminal/tasks/__init__.py +5 -0
  508. autocoder/terminal/tasks/background.py +77 -0
  509. autocoder/terminal/tasks/task_event.py +70 -0
  510. autocoder/terminal/ui/__init__.py +13 -0
  511. autocoder/terminal/ui/completer.py +268 -0
  512. autocoder/terminal/ui/keybindings.py +75 -0
  513. autocoder/terminal/ui/session.py +41 -0
  514. autocoder/terminal/ui/toolbar.py +64 -0
  515. autocoder/terminal/utils/__init__.py +13 -0
  516. autocoder/terminal/utils/errors.py +18 -0
  517. autocoder/terminal/utils/paths.py +19 -0
  518. autocoder/terminal/utils/shell.py +43 -0
  519. autocoder/terminal_v3/__init__.py +10 -0
  520. autocoder/terminal_v3/app.py +201 -0
  521. autocoder/terminal_v3/handlers/__init__.py +5 -0
  522. autocoder/terminal_v3/handlers/command_handler.py +131 -0
  523. autocoder/terminal_v3/models/__init__.py +6 -0
  524. autocoder/terminal_v3/models/conversation_buffer.py +214 -0
  525. autocoder/terminal_v3/models/message.py +50 -0
  526. autocoder/terminal_v3/models/tool_display.py +247 -0
  527. autocoder/terminal_v3/ui/__init__.py +7 -0
  528. autocoder/terminal_v3/ui/keybindings.py +56 -0
  529. autocoder/terminal_v3/ui/layout.py +141 -0
  530. autocoder/terminal_v3/ui/styles.py +43 -0
  531. autocoder/tsproject/__init__.py +23 -23
  532. autocoder/utils/auto_coder_utils/chat_stream_out.py +1 -1
  533. autocoder/utils/llms.py +88 -80
  534. autocoder/utils/math_utils.py +101 -0
  535. autocoder/utils/model_provider_selector.py +16 -4
  536. autocoder/utils/operate_config_api.py +33 -5
  537. autocoder/utils/thread_utils.py +2 -2
  538. autocoder/version.py +4 -2
  539. autocoder/workflow_agents/__init__.py +84 -0
  540. autocoder/workflow_agents/agent.py +143 -0
  541. autocoder/workflow_agents/exceptions.py +573 -0
  542. autocoder/workflow_agents/executor.py +489 -0
  543. autocoder/workflow_agents/loader.py +737 -0
  544. autocoder/workflow_agents/runner.py +267 -0
  545. autocoder/workflow_agents/types.py +172 -0
  546. autocoder/workflow_agents/utils.py +434 -0
  547. autocoder/workflow_agents/workflow_manager.py +211 -0
  548. auto_coder-0.1.400.dist-info/METADATA +0 -396
  549. auto_coder-0.1.400.dist-info/RECORD +0 -425
  550. auto_coder-0.1.400.dist-info/licenses/LICENSE +0 -201
  551. autocoder/auto_coder_server.py +0 -672
  552. autocoder/benchmark.py +0 -138
  553. autocoder/common/ac_style_command_parser/example.py +0 -7
  554. autocoder/common/cleaner.py +0 -31
  555. autocoder/common/command_completer_v2.py +0 -615
  556. autocoder/common/directory_cache/__init__.py +0 -1
  557. autocoder/common/directory_cache/cache.py +0 -192
  558. autocoder/common/directory_cache/test_cache.py +0 -190
  559. autocoder/common/file_checkpoint/examples.py +0 -217
  560. autocoder/common/llm_friendly_package_example.py +0 -138
  561. autocoder/common/llm_friendly_package_test.py +0 -63
  562. autocoder/common/pull_requests/test_module.py +0 -1
  563. autocoder/common/rulefiles/autocoderrules_utils.py +0 -484
  564. autocoder/common/text.py +0 -30
  565. autocoder/common/v2/agent/agentic_edit_tools/list_package_info_tool_resolver.py +0 -42
  566. autocoder/common/v2/agent/agentic_edit_tools/test_execute_command_tool_resolver.py +0 -70
  567. autocoder/common/v2/agent/agentic_edit_tools/test_search_files_tool_resolver.py +0 -163
  568. autocoder/common/v2/agent/agentic_tool_display.py +0 -183
  569. autocoder/plugins/dynamic_completion_example.py +0 -148
  570. autocoder/plugins/sample_plugin.py +0 -160
  571. autocoder/sdk/cli/__main__.py +0 -26
  572. autocoder/sdk/cli/completion_wrapper.py +0 -38
  573. autocoder/sdk/cli/install_completion.py +0 -301
  574. autocoder/sdk/models/messages.py +0 -209
  575. autocoder/sdk/session/__init__.py +0 -32
  576. autocoder/sdk/session/session.py +0 -106
  577. autocoder/sdk/session/session_manager.py +0 -56
  578. {auto_coder-0.1.400.dist-info → auto_coder-2.0.0.dist-info}/top_level.txt +0 -0
  579. /autocoder/{sdk/example.py → common/agent_query_queue/__init__.py} +0 -0
@@ -0,0 +1,502 @@
1
+
2
+
3
+ """
4
+ Test cases for ConversationNormalizer
5
+
6
+ This module contains comprehensive tests for the conversation normalization functionality,
7
+ including merge and delete strategies, edge cases, and validation.
8
+ """
9
+
10
+ import pytest
11
+ from typing import List, Dict, Any
12
+ from autocoder.common.pruner.conversation_normalizer import (
13
+ ConversationNormalizer,
14
+ NormalizationStrategy,
15
+ NormalizationResult
16
+ )
17
+
18
+
19
+ class TestConversationNormalizer:
20
+ """测试会话规整化器的核心功能"""
21
+
22
+ def setup_method(self):
23
+ """测试前的设置"""
24
+ self.normalizer = ConversationNormalizer()
25
+
26
+ def test_merge_strategy_basic(self):
27
+ """测试基本的合并策略"""
28
+ # 测试目标:验证连续的相同角色消息能够正确合并
29
+ conversations = [
30
+ {"role": "user", "content": "第一个用户消息"},
31
+ {"role": "user", "content": "第二个用户消息"},
32
+ {"role": "assistant", "content": "助手回复"}
33
+ ]
34
+
35
+ result = self.normalizer.normalize_conversations(
36
+ conversations,
37
+ strategy=NormalizationStrategy.MERGE
38
+ )
39
+
40
+ # 验证结果
41
+ assert result.original_count == 3
42
+ assert result.normalized_count == 2
43
+ assert len(result.changes_made) == 1
44
+ assert result.strategy_used == "merge"
45
+
46
+ # 验证合并后的内容
47
+ normalized = result.normalized_conversations
48
+ assert len(normalized) == 2
49
+ assert normalized[0]["role"] == "user"
50
+ assert "[消息 1]" in normalized[0]["content"]
51
+ assert "[消息 2]" in normalized[0]["content"]
52
+ assert "第一个用户消息" in normalized[0]["content"]
53
+ assert "第二个用户消息" in normalized[0]["content"]
54
+ assert normalized[1]["role"] == "assistant"
55
+ assert normalized[1]["content"] == "助手回复"
56
+
57
+ def test_delete_strategy_basic(self):
58
+ """测试基本的删除策略"""
59
+ # 测试目标:验证连续的相同角色消息只保留第一个
60
+ conversations = [
61
+ {"role": "user", "content": "第一个用户消息"},
62
+ {"role": "user", "content": "第二个用户消息"},
63
+ {"role": "assistant", "content": "助手回复"}
64
+ ]
65
+
66
+ result = self.normalizer.normalize_conversations(
67
+ conversations,
68
+ strategy=NormalizationStrategy.DELETE
69
+ )
70
+
71
+ # 验证结果
72
+ assert result.original_count == 3
73
+ assert result.normalized_count == 2
74
+ assert len(result.changes_made) == 1
75
+ assert result.strategy_used == "delete"
76
+
77
+ # 验证删除后的内容
78
+ normalized = result.normalized_conversations
79
+ assert len(normalized) == 2
80
+ assert normalized[0]["role"] == "user"
81
+ assert normalized[0]["content"] == "第一个用户消息" # 只保留第一个
82
+ assert normalized[1]["role"] == "assistant"
83
+ assert normalized[1]["content"] == "助手回复"
84
+
85
+ # 验证变更记录
86
+ change = result.changes_made[0]
87
+ assert change["action"] == "delete"
88
+ assert change["deleted_count"] == 1
89
+ assert change["kept_message"]["content"] == "第一个用户消息"
90
+
91
+ def test_complex_conversation_merge(self):
92
+ """测试复杂会话的合并策略"""
93
+ # 测试目标:验证多个连续组的正确处理
94
+ conversations = [
95
+ {"role": "user", "content": "用户消息1"},
96
+ {"role": "user", "content": "用户消息2"},
97
+ {"role": "user", "content": "用户消息3"},
98
+ {"role": "assistant", "content": "助手消息1"},
99
+ {"role": "assistant", "content": "助手消息2"},
100
+ {"role": "user", "content": "用户消息4"},
101
+ {"role": "assistant", "content": "助手消息3"}
102
+ ]
103
+
104
+ result = self.normalizer.normalize_conversations(
105
+ conversations,
106
+ strategy=NormalizationStrategy.MERGE
107
+ )
108
+
109
+ # 验证结果
110
+ assert result.original_count == 7
111
+ assert result.normalized_count == 4
112
+ assert len(result.changes_made) == 2 # 两个合并操作
113
+
114
+ normalized = result.normalized_conversations
115
+ assert len(normalized) == 4
116
+
117
+ # 验证第一个合并(3个user消息)
118
+ assert normalized[0]["role"] == "user"
119
+ assert "[消息 1]" in normalized[0]["content"]
120
+ assert "[消息 2]" in normalized[0]["content"]
121
+ assert "[消息 3]" in normalized[0]["content"]
122
+
123
+ # 验证第二个合并(2个assistant消息)
124
+ assert normalized[1]["role"] == "assistant"
125
+ assert "[消息 1]" in normalized[1]["content"]
126
+ assert "[消息 2]" in normalized[1]["content"]
127
+
128
+ # 验证未合并的消息
129
+ assert normalized[2]["role"] == "user"
130
+ assert normalized[2]["content"] == "用户消息4"
131
+ assert normalized[3]["role"] == "assistant"
132
+ assert normalized[3]["content"] == "助手消息3"
133
+
134
+ def test_no_normalization_needed(self):
135
+ """测试不需要规整化的正常会话"""
136
+ # 测试目标:验证正常的交替会话不会被修改
137
+ conversations = [
138
+ {"role": "user", "content": "用户消息"},
139
+ {"role": "assistant", "content": "助手回复"},
140
+ {"role": "user", "content": "用户追问"},
141
+ {"role": "assistant", "content": "助手再回复"}
142
+ ]
143
+
144
+ result = self.normalizer.normalize_conversations(conversations)
145
+
146
+ # 验证结果
147
+ assert result.original_count == 4
148
+ assert result.normalized_count == 4
149
+ assert len(result.changes_made) == 0
150
+ assert result.normalized_conversations == conversations
151
+
152
+ def test_empty_conversations(self):
153
+ """测试空会话列表"""
154
+ # 测试目标:验证空输入的正确处理
155
+ result = self.normalizer.normalize_conversations([])
156
+
157
+ assert result.original_count == 0
158
+ assert result.normalized_count == 0
159
+ assert len(result.changes_made) == 0
160
+ assert result.normalized_conversations == []
161
+
162
+ def test_single_message(self):
163
+ """测试单条消息"""
164
+ # 测试目标:验证单条消息不会被修改
165
+ conversations = [{"role": "user", "content": "单条消息"}]
166
+
167
+ result = self.normalizer.normalize_conversations(conversations)
168
+
169
+ assert result.original_count == 1
170
+ assert result.normalized_count == 1
171
+ assert len(result.changes_made) == 0
172
+ assert result.normalized_conversations == conversations
173
+
174
+ def test_preserve_additional_fields(self):
175
+ """测试保留消息的额外字段"""
176
+ # 测试目标:验证合并时保留除role和content外的其他字段
177
+ conversations = [
178
+ {"role": "user", "content": "消息1", "timestamp": "2024-01-01", "id": "msg1"},
179
+ {"role": "user", "content": "消息2", "timestamp": "2024-01-02", "id": "msg2"},
180
+ {"role": "assistant", "content": "回复"}
181
+ ]
182
+
183
+ result = self.normalizer.normalize_conversations(
184
+ conversations,
185
+ strategy=NormalizationStrategy.MERGE
186
+ )
187
+
188
+ normalized = result.normalized_conversations
189
+ merged_msg = normalized[0]
190
+
191
+ # 验证额外字段被保留(来自第一条消息)
192
+ assert "timestamp" in merged_msg
193
+ assert "id" in merged_msg
194
+ assert merged_msg["timestamp"] == "2024-01-01"
195
+ assert merged_msg["id"] == "msg1"
196
+
197
+
198
+ class TestConversationStructureAnalysis:
199
+ """测试会话结构分析功能"""
200
+
201
+ def setup_method(self):
202
+ """测试前的设置"""
203
+ self.normalizer = ConversationNormalizer()
204
+
205
+ def test_analyze_normal_structure(self):
206
+ """测试分析正常的会话结构"""
207
+ # 测试目标:验证正常会话结构的分析结果
208
+ conversations = [
209
+ {"role": "user", "content": "用户消息"},
210
+ {"role": "assistant", "content": "助手回复"},
211
+ {"role": "user", "content": "用户追问"},
212
+ {"role": "assistant", "content": "助手再回复"}
213
+ ]
214
+
215
+ analysis = self.normalizer.analyze_conversation_structure(conversations)
216
+
217
+ assert analysis["total_messages"] == 4
218
+ assert analysis["role_distribution"] == {"user": 2, "assistant": 2}
219
+ assert analysis["consecutive_groups"] == []
220
+ assert analysis["needs_normalization"] == False
221
+ assert len(analysis["issues"]) == 0
222
+
223
+ def test_analyze_problematic_structure(self):
224
+ """测试分析有问题的会话结构"""
225
+ # 测试目标:验证问题会话结构的正确识别
226
+ conversations = [
227
+ {"role": "user", "content": "消息1"},
228
+ {"role": "user", "content": "消息2"},
229
+ {"role": "user", "content": "消息3"},
230
+ {"role": "assistant", "content": "回复1"},
231
+ {"role": "assistant", "content": "回复2"}
232
+ ]
233
+
234
+ analysis = self.normalizer.analyze_conversation_structure(conversations)
235
+
236
+ assert analysis["total_messages"] == 5
237
+ assert analysis["role_distribution"] == {"user": 3, "assistant": 2}
238
+ assert len(analysis["consecutive_groups"]) == 2
239
+ assert analysis["needs_normalization"] == True
240
+ assert len(analysis["issues"]) >= 2
241
+
242
+ # 验证连续组信息
243
+ user_group = analysis["consecutive_groups"][0]
244
+ assert user_group["role"] == "user"
245
+ assert user_group["count"] == 3
246
+ assert user_group["start_index"] == 0
247
+
248
+ assistant_group = analysis["consecutive_groups"][1]
249
+ assert assistant_group["role"] == "assistant"
250
+ assert assistant_group["count"] == 2
251
+ assert assistant_group["start_index"] == 3
252
+
253
+ def test_analyze_empty_conversations(self):
254
+ """测试分析空会话"""
255
+ # 测试目标:验证空会话的分析结果
256
+ analysis = self.normalizer.analyze_conversation_structure([])
257
+
258
+ assert analysis["total_messages"] == 0
259
+ assert analysis["role_distribution"] == {}
260
+ assert analysis["consecutive_groups"] == []
261
+ assert analysis["needs_normalization"] == False
262
+ assert analysis["issues"] == []
263
+
264
+
265
+ class TestConversationValidation:
266
+ """测试会话验证功能"""
267
+
268
+ def setup_method(self):
269
+ """测试前的设置"""
270
+ self.normalizer = ConversationNormalizer()
271
+
272
+ def test_validate_perfect_conversation(self):
273
+ """测试验证完美的会话"""
274
+ # 测试目标:验证理想的user-assistant交替模式
275
+ conversations = [
276
+ {"role": "user", "content": "用户消息"},
277
+ {"role": "assistant", "content": "助手回复"},
278
+ {"role": "user", "content": "用户追问"},
279
+ {"role": "assistant", "content": "助手再回复"}
280
+ ]
281
+
282
+ validation = self.normalizer.validate_normalized_conversation(conversations)
283
+
284
+ assert validation["is_valid"] == True
285
+ assert len(validation["errors"]) == 0
286
+ assert len(validation["warnings"]) == 0
287
+ assert validation["structure_info"]["follows_user_assistant_pattern"] == True
288
+ assert validation["structure_info"]["starts_with_user"] == True
289
+ assert validation["structure_info"]["ends_with_assistant"] == True
290
+
291
+ def test_validate_consecutive_roles(self):
292
+ """测试验证连续相同角色的问题"""
293
+ # 测试目标:验证连续相同角色被正确识别为错误
294
+ conversations = [
295
+ {"role": "user", "content": "用户消息1"},
296
+ {"role": "user", "content": "用户消息2"},
297
+ {"role": "assistant", "content": "助手回复"}
298
+ ]
299
+
300
+ validation = self.normalizer.validate_normalized_conversation(conversations)
301
+
302
+ assert validation["is_valid"] == False
303
+ assert len(validation["errors"]) == 1
304
+ assert "连续的 'user' 角色" in validation["errors"][0]
305
+
306
+ def test_validate_wrong_pattern(self):
307
+ """测试验证错误的角色模式"""
308
+ # 测试目标:验证不符合user-assistant交替模式的会话
309
+ conversations = [
310
+ {"role": "assistant", "content": "助手先开始"},
311
+ {"role": "user", "content": "用户回应"},
312
+ {"role": "user", "content": "用户继续"}
313
+ ]
314
+
315
+ validation = self.normalizer.validate_normalized_conversation(conversations)
316
+
317
+ assert validation["structure_info"]["follows_user_assistant_pattern"] == False
318
+ assert validation["structure_info"]["starts_with_user"] == False
319
+ assert validation["structure_info"]["ends_with_assistant"] == False
320
+ assert len(validation["warnings"]) >= 2 # 至少有模式不匹配的警告
321
+
322
+
323
+ class TestEdgeCases:
324
+ """测试边缘情况"""
325
+
326
+ def setup_method(self):
327
+ """测试前的设置"""
328
+ self.normalizer = ConversationNormalizer()
329
+
330
+ def test_empty_content_messages(self):
331
+ """测试空内容消息的处理"""
332
+ # 测试目标:验证空内容消息的正确处理
333
+ conversations = [
334
+ {"role": "user", "content": ""},
335
+ {"role": "user", "content": "有内容的消息"},
336
+ {"role": "assistant", "content": "回复"}
337
+ ]
338
+
339
+ result = self.normalizer.normalize_conversations(
340
+ conversations,
341
+ strategy=NormalizationStrategy.MERGE
342
+ )
343
+
344
+ # 验证空内容也被正确合并
345
+ assert result.normalized_count == 2
346
+ normalized = result.normalized_conversations
347
+ assert "[消息 2]" in normalized[0]["content"]
348
+ assert "有内容的消息" in normalized[0]["content"]
349
+
350
+ def test_missing_role_field(self):
351
+ """测试缺少role字段的消息"""
352
+ # 测试目标:验证缺少role字段时的处理
353
+ conversations = [
354
+ {"content": "没有role字段"},
355
+ {"content": "也没有role字段"},
356
+ {"role": "assistant", "content": "有role字段"}
357
+ ]
358
+
359
+ result = self.normalizer.normalize_conversations(conversations)
360
+
361
+ # 验证缺少role字段的消息被当作相同角色处理
362
+ assert result.normalized_count == 2
363
+ assert len(result.changes_made) == 1
364
+
365
+ def test_unknown_role(self):
366
+ """测试未知角色的处理"""
367
+ # 测试目标:验证未知角色的正确处理
368
+ conversations = [
369
+ {"role": "system", "content": "系统消息1"},
370
+ {"role": "system", "content": "系统消息2"},
371
+ {"role": "user", "content": "用户消息"},
372
+ {"role": "assistant", "content": "助手回复"}
373
+ ]
374
+
375
+ result = self.normalizer.normalize_conversations(
376
+ conversations,
377
+ strategy=NormalizationStrategy.MERGE
378
+ )
379
+
380
+ # 验证系统消息被正确合并
381
+ assert result.normalized_count == 3
382
+ normalized = result.normalized_conversations
383
+ assert normalized[0]["role"] == "system"
384
+ assert "[消息 1]" in normalized[0]["content"]
385
+ assert "[消息 2]" in normalized[0]["content"]
386
+
387
+ def test_all_same_role(self):
388
+ """测试全部相同角色的会话"""
389
+ # 测试目标:验证全部相同角色时的处理
390
+ conversations = [
391
+ {"role": "user", "content": "消息1"},
392
+ {"role": "user", "content": "消息2"},
393
+ {"role": "user", "content": "消息3"},
394
+ {"role": "user", "content": "消息4"}
395
+ ]
396
+
397
+ # 测试合并策略
398
+ merge_result = self.normalizer.normalize_conversations(
399
+ conversations,
400
+ strategy=NormalizationStrategy.MERGE
401
+ )
402
+ assert merge_result.normalized_count == 1
403
+ assert len(merge_result.changes_made) == 1
404
+
405
+ # 测试删除策略
406
+ delete_result = self.normalizer.normalize_conversations(
407
+ conversations,
408
+ strategy=NormalizationStrategy.DELETE
409
+ )
410
+ assert delete_result.normalized_count == 1
411
+ assert len(delete_result.changes_made) == 1
412
+ assert delete_result.changes_made[0]["deleted_count"] == 3
413
+
414
+
415
+ class TestIntegrationScenarios:
416
+ """测试集成场景"""
417
+
418
+ def setup_method(self):
419
+ """测试前的设置"""
420
+ self.normalizer = ConversationNormalizer()
421
+
422
+ def test_real_world_scenario_1(self):
423
+ """测试真实场景1:用户多次提问后得到回复"""
424
+ # 测试目标:模拟用户连续提问的真实场景
425
+ conversations = [
426
+ {"role": "user", "content": "我想了解Python"},
427
+ {"role": "user", "content": "特别是关于数据结构的部分"},
428
+ {"role": "user", "content": "你能详细介绍一下列表吗?"},
429
+ {"role": "assistant", "content": "好的,我来详细介绍Python中的列表..."},
430
+ {"role": "user", "content": "那字典呢?"},
431
+ {"role": "assistant", "content": "字典是另一种重要的数据结构..."}
432
+ ]
433
+
434
+ # 分析原始结构
435
+ analysis = self.normalizer.analyze_conversation_structure(conversations)
436
+ assert analysis["needs_normalization"] == True
437
+ assert len(analysis["consecutive_groups"]) == 1
438
+
439
+ # 应用合并策略
440
+ result = self.normalizer.normalize_conversations(
441
+ conversations,
442
+ strategy=NormalizationStrategy.MERGE
443
+ )
444
+
445
+ assert result.normalized_count == 4
446
+ normalized = result.normalized_conversations
447
+
448
+ # 验证用户的三个问题被合并
449
+ assert normalized[0]["role"] == "user"
450
+ assert "Python" in normalized[0]["content"]
451
+ assert "数据结构" in normalized[0]["content"]
452
+ assert "列表" in normalized[0]["content"]
453
+
454
+ # 验证后续对话保持不变
455
+ assert normalized[1]["content"] == "好的,我来详细介绍Python中的列表..."
456
+ assert normalized[2]["content"] == "那字典呢?"
457
+ assert normalized[3]["content"] == "字典是另一种重要的数据结构..."
458
+
459
+ # 验证规整化后的会话
460
+ validation = self.normalizer.validate_normalized_conversation(normalized)
461
+ assert validation["is_valid"] == True
462
+
463
+ def test_real_world_scenario_2(self):
464
+ """测试真实场景2:助手多次回复后用户提问"""
465
+ # 测试目标:模拟助手连续回复的真实场景
466
+ conversations = [
467
+ {"role": "user", "content": "请解释机器学习"},
468
+ {"role": "assistant", "content": "机器学习是人工智能的一个分支..."},
469
+ {"role": "assistant", "content": "它主要包括监督学习、无监督学习..."},
470
+ {"role": "assistant", "content": "常见的算法有线性回归、决策树..."},
471
+ {"role": "user", "content": "能举个具体例子吗?"},
472
+ {"role": "assistant", "content": "当然,比如预测房价..."}
473
+ ]
474
+
475
+ # 应用删除策略
476
+ result = self.normalizer.normalize_conversations(
477
+ conversations,
478
+ strategy=NormalizationStrategy.DELETE
479
+ )
480
+
481
+ assert result.normalized_count == 4
482
+ normalized = result.normalized_conversations
483
+
484
+ # 验证只保留第一个助手回复
485
+ assert normalized[1]["role"] == "assistant"
486
+ assert normalized[1]["content"] == "机器学习是人工智能的一个分支..."
487
+
488
+ # 验证变更记录
489
+ change = result.changes_made[0]
490
+ assert change["action"] == "delete"
491
+ assert change["deleted_count"] == 2
492
+
493
+ # 验证规整化后的会话
494
+ validation = self.normalizer.validate_normalized_conversation(normalized)
495
+ assert validation["is_valid"] == True
496
+
497
+
498
+ if __name__ == "__main__":
499
+ # 运行所有测试
500
+ pytest.main([__file__, "-v", "-s"])
501
+
502
+