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,546 @@
1
+ import pytest
2
+ import tempfile
3
+ import shutil
4
+ import os
5
+ from unittest.mock import MagicMock, patch
6
+ from autocoder.common.pruner.context_pruner import PruneContext
7
+ from autocoder.common import AutoCoderArgs, SourceCode
8
+ from autocoder.sdk import get_llm, init_project_if_required
9
+ from autocoder.common.tokens import count_string_tokens
10
+
11
+
12
+ class TestPruneContextExtractStrategy:
13
+ """Test suite for PruneContext extract strategy"""
14
+
15
+ @pytest.fixture
16
+ def temp_test_dir(self):
17
+ """提供一个临时的、测试后自动清理的目录"""
18
+ # 保存原始工作目录
19
+ original_cwd = os.getcwd()
20
+ temp_dir = tempfile.mkdtemp()
21
+ try:
22
+ yield temp_dir
23
+ finally:
24
+ # 确保恢复到原始目录,即使出现异常
25
+ try:
26
+ os.chdir(original_cwd)
27
+ except OSError:
28
+ # 如果原始目录也不存在,则切换到用户主目录
29
+ os.chdir(os.path.expanduser("~"))
30
+ # 删除临时目录
31
+ if os.path.exists(temp_dir):
32
+ shutil.rmtree(temp_dir)
33
+
34
+ @pytest.fixture
35
+ def mock_args(self):
36
+ """Create mock AutoCoderArgs for testing"""
37
+ return AutoCoderArgs(
38
+ source_dir=".",
39
+ context_prune=True,
40
+ context_prune_strategy="extract",
41
+ conversation_prune_safe_zone_tokens=30, # 这个不对context_prunner 生效
42
+ context_prune_sliding_window_size=10,
43
+ context_prune_sliding_window_overlap=2,
44
+ query="如何实现加法和减法运算?"
45
+ )
46
+
47
+ @pytest.fixture
48
+ def real_llm(self):
49
+ """创建真实的LLM对象"""
50
+ llm = get_llm("v3_chat", product_mode="lite")
51
+ return llm
52
+
53
+ @pytest.fixture
54
+ def pruner(self, mock_args, real_llm):
55
+ """Create PruneContext instance for testing"""
56
+ # 对 context_prunner 生效的是 max_tokens这里
57
+ return PruneContext(max_tokens=60, args=mock_args, llm=real_llm)
58
+
59
+ @pytest.fixture
60
+ def verbose_pruner(self, mock_args, real_llm):
61
+ """Create PruneContext instance with verbose=True for testing"""
62
+ return PruneContext(max_tokens=60, args=mock_args, llm=real_llm, verbose=True)
63
+
64
+ @pytest.fixture
65
+ def sample_file_sources(self, temp_test_dir):
66
+ """Sample file sources for testing
67
+ Creates a simulated project structure in the temporary directory
68
+ """
69
+ # 创建项目结构
70
+ src_dir = os.path.join(temp_test_dir, "src")
71
+ utils_dir = os.path.join(src_dir, "utils")
72
+ os.makedirs(utils_dir, exist_ok=True)
73
+
74
+ # 创建 __init__.py 文件使其成为有效的 Python 包
75
+ with open(os.path.join(src_dir, "__init__.py"), "w") as f:
76
+ f.write("# src package")
77
+ with open(os.path.join(utils_dir, "__init__.py"), "w") as f:
78
+ f.write("# utils package")
79
+
80
+ # 创建数学工具模块
81
+ math_utils_content = '''def add(a, b):
82
+ """加法函数"""
83
+ return a + b
84
+
85
+ def subtract(a, b):
86
+ """减法函数"""
87
+ return a - b
88
+
89
+ def multiply(a, b):
90
+ """乘法函数"""
91
+ return a * b
92
+
93
+ def divide(a, b):
94
+ """除法函数"""
95
+ if b == 0:
96
+ raise ValueError("Cannot divide by zero")
97
+ return a / b
98
+ '''
99
+ math_utils_path = os.path.join(utils_dir, "math_utils.py")
100
+ with open(math_utils_path, "w") as f:
101
+ f.write(math_utils_content)
102
+
103
+ # 创建字符串工具模块
104
+ string_utils_content = '''def format_string(s):
105
+ """格式化字符串"""
106
+ return s.strip().lower()
107
+
108
+ def reverse_string(s):
109
+ """反转字符串"""
110
+ return s[::-1]
111
+
112
+ def count_characters(s):
113
+ """计算字符数"""
114
+ return len(s)
115
+ '''
116
+ string_utils_path = os.path.join(utils_dir, "string_utils.py")
117
+ with open(string_utils_path, "w") as f:
118
+ f.write(string_utils_content)
119
+
120
+ # 创建主程序文件
121
+ main_content = '''from utils.math_utils import add, subtract
122
+ from utils.string_utils import format_string
123
+
124
+ def main():
125
+ print("计算结果:", add(5, 3))
126
+ print("格式化结果:", format_string(" Hello World "))
127
+
128
+ if __name__ == "__main__":
129
+ main()
130
+ '''
131
+ main_path = os.path.join(src_dir, "main.py")
132
+ with open(main_path, "w") as f:
133
+ f.write(main_content)
134
+
135
+ # 创建 README 文件
136
+ readme_content = '''# 测试项目
137
+
138
+ 这是一个用于测试的模拟项目结构。
139
+
140
+ ## 功能
141
+
142
+ - 数学运算
143
+ - 字符串处理
144
+ '''
145
+ readme_path = os.path.join(temp_test_dir, "README.md")
146
+ with open(readme_path, "w") as f:
147
+ f.write(readme_content)
148
+
149
+ # 初始化该项目
150
+ # 保存当前工作目录
151
+ original_cwd = os.getcwd()
152
+ try:
153
+ os.chdir(temp_test_dir)
154
+ init_project_if_required(target_dir=temp_test_dir)
155
+ finally:
156
+ # 立即恢复工作目录,避免影响后续测试
157
+ os.chdir(original_cwd)
158
+
159
+ # 返回与原来相同的 SourceCode 对象列表,但使用相对路径作为 module_name
160
+ v = [
161
+ SourceCode(
162
+ module_name="src/utils/math_utils.py",
163
+ source_code=math_utils_content,
164
+ tokens=count_string_tokens(math_utils_content)
165
+ ),
166
+ SourceCode(
167
+ module_name="src/utils/string_utils.py",
168
+ source_code=string_utils_content,
169
+ tokens=count_string_tokens(string_utils_content)
170
+ ),
171
+ SourceCode(
172
+ module_name="src/main.py",
173
+ source_code=main_content,
174
+ tokens=count_string_tokens(main_content)
175
+ )
176
+ ]
177
+
178
+ return v
179
+
180
+ @pytest.fixture
181
+ def sample_conversations(self):
182
+ """Sample conversations for testing"""
183
+ return [
184
+ {"role": "user", "content": "如何实现加法和减法运算?"},
185
+ {"role": "assistant", "content": "我来帮你实现加法和减法运算。"}
186
+ ]
187
+
188
+ def test_extract_strategy_basic(self, pruner, sample_file_sources, sample_conversations):
189
+ """测试extract策略的基本功能"""
190
+
191
+ # 计算输入的总token数
192
+ original_total_tokens = sum(source.tokens for source in sample_file_sources)
193
+ print(f"原始总token数: {original_total_tokens}")
194
+
195
+ result = pruner.handle_overflow(
196
+ file_sources=sample_file_sources,
197
+ conversations=sample_conversations,
198
+ strategy="extract"
199
+ )
200
+
201
+ # 验证结果基本结构
202
+ assert isinstance(result, list), "应该返回文件列表"
203
+ print(f"返回文件数量: {len(result)}")
204
+
205
+ # 验证返回的是SourceCode对象
206
+ for item in result:
207
+ assert isinstance(item, SourceCode), "返回的应该是SourceCode对象"
208
+ assert hasattr(item, 'module_name'), "SourceCode应该有module_name属性"
209
+ assert hasattr(item, 'source_code'), "SourceCode应该有source_code属性"
210
+
211
+ # 如果有结果,验证token压缩效果
212
+ if len(result) > 0:
213
+ # 计算输出的总token数
214
+ result_total_tokens = sum(item.tokens for item in result)
215
+ print(f"处理后总token数: {result_total_tokens}")
216
+
217
+ # 验证token数确实减少了
218
+ assert result_total_tokens < original_total_tokens, f"Token数应该减少,原始: {original_total_tokens}, 处理后: {result_total_tokens}"
219
+
220
+ # 计算压缩率
221
+ compression_rate = (original_total_tokens - result_total_tokens) / original_total_tokens * 100
222
+ print(f"Token压缩率: {compression_rate:.1f}%")
223
+ assert compression_rate > 0, "应该有有效的压缩率"
224
+
225
+ # 验证与查询相关的函数是否在结果中(用户查询:"如何实现加法和减法运算?")
226
+ combined_content = "\n".join(item.source_code for item in result)
227
+ print(f"合并后的内容长度: {len(combined_content)} 字符")
228
+
229
+ # 检查加法和减法相关的函数是否存在
230
+ has_add_function = "def add(" in combined_content or "add(" in combined_content
231
+ has_subtract_function = "def subtract(" in combined_content or "subtract(" in combined_content
232
+
233
+ print(f"包含add函数: {has_add_function}")
234
+ print(f"包含subtract函数: {has_subtract_function}")
235
+
236
+ # 至少应该包含其中一个相关函数
237
+ assert has_add_function or has_subtract_function, "裁剪后的结果应该包含与查询相关的加法或减法函数"
238
+
239
+ # 验证math_utils.py是否在结果中(因为它包含相关函数)
240
+ math_utils_files = [item for item in result if "math_utils.py" in item.module_name]
241
+ if math_utils_files:
242
+ math_utils_content = math_utils_files[0].source_code
243
+ print(f"math_utils.py处理后内容:\n{math_utils_content}")
244
+
245
+ # 验证包含Snippets标记(说明经过了代码片段抽取)
246
+ assert "Snippets:" in math_utils_content, "math_utils.py应该包含代码片段抽取标记"
247
+
248
+ else:
249
+ print("⚠️ Extract策略返回空结果(这可能发生在LLM超时或其他异常情况下)")
250
+
251
+ def test_sliding_window_split(self, pruner):
252
+ """测试滑动窗口分割功能"""
253
+ # 创建一个较长的内容用于测试(20行)
254
+ content = "\n".join([f"line {i}: some content here" for i in range(1, 21)])
255
+ content_lines = content.split('\n')
256
+ total_lines = len(content_lines)
257
+
258
+ print(f"测试内容总行数: {total_lines}")
259
+
260
+ # 测试不同的滑动窗口配置
261
+ test_cases = [
262
+ {
263
+ "window_size": 5,
264
+ "overlap": 2,
265
+ "expected_chunks": 7, # 基于实际运行结果
266
+ "description": "标准滑动窗口配置"
267
+ },
268
+ {
269
+ "window_size": 3,
270
+ "overlap": 1,
271
+ "expected_chunks": 10, # 基于实际运行结果
272
+ "description": "小窗口高重叠配置"
273
+ },
274
+ {
275
+ "window_size": 10,
276
+ "overlap": 3,
277
+ "expected_chunks": 3, # 基于实际运行结果
278
+ "description": "大窗口中等重叠配置"
279
+ },
280
+ {
281
+ "window_size": 7,
282
+ "overlap": 0,
283
+ "expected_chunks": 3, # 基于实际运行结果
284
+ "description": "无重叠配置"
285
+ }
286
+ ]
287
+
288
+ for case in test_cases:
289
+ window_size = case["window_size"]
290
+ overlap = case["overlap"]
291
+ expected_chunks = case["expected_chunks"]
292
+ description = case["description"]
293
+
294
+ print(f"\n🔍 测试 {description}: 窗口={window_size}, 重叠={overlap}")
295
+
296
+ chunks = pruner._split_content_with_sliding_window(
297
+ content=content,
298
+ window_size=window_size,
299
+ overlap=overlap
300
+ )
301
+
302
+ # 验证基本结构
303
+ assert isinstance(chunks, list), f"应该返回chunk列表 ({description})"
304
+ assert len(chunks) == expected_chunks, f"应该有 {expected_chunks} 个chunks,实际: {len(chunks)} ({description})"
305
+
306
+ # 验证chunk结构和内容
307
+ for i, chunk in enumerate(chunks):
308
+ assert isinstance(chunk, tuple), f"Chunk {i+1} 应该是元组 ({description})"
309
+ assert len(chunk) == 3, f"Chunk {i+1} 应该包含3个元素 ({description})"
310
+
311
+ start_line, end_line, chunk_content = chunk
312
+ assert isinstance(start_line, int), f"Chunk {i+1} 起始行号应该是整数 ({description})"
313
+ assert isinstance(end_line, int), f"Chunk {i+1} 结束行号应该是整数 ({description})"
314
+ assert isinstance(chunk_content, str), f"Chunk {i+1} 内容应该是字符串 ({description})"
315
+ assert start_line <= end_line, f"Chunk {i+1} 起始行号应该 <= 结束行号 ({description})"
316
+
317
+ # 验证行号范围合理
318
+ assert 1 <= start_line <= total_lines, f"Chunk {i+1} 起始行号应该在1-{total_lines}范围内 ({description})"
319
+ assert 1 <= end_line <= total_lines, f"Chunk {i+1} 结束行号应该在1-{total_lines}范围内 ({description})"
320
+
321
+ # 验证内容行数与行号范围一致
322
+ chunk_lines = chunk_content.split('\n')
323
+ expected_line_count = end_line - start_line + 1
324
+ # 注意:由于chunk_content中可能包含行号前缀,实际行数可能不同
325
+ # 我们主要验证内容不为空且合理
326
+ assert len(chunk_content) > 0, f"Chunk {i+1} 内容不应为空 ({description})"
327
+
328
+ print(f" Chunk {i+1}: 行 {start_line}-{end_line} ({len(chunk_lines)} 行)")
329
+
330
+ # 验证重叠逻辑
331
+ if overlap > 0 and len(chunks) > 1:
332
+ for i in range(len(chunks) - 1):
333
+ current_start, current_end, _ = chunks[i]
334
+ next_start, next_end, _ = chunks[i + 1]
335
+
336
+ # 验证有重叠
337
+ if i < len(chunks) - 2: # 不是最后一个chunk对
338
+ overlap_lines = current_end - next_start + 1
339
+ assert overlap_lines >= overlap, f"Chunk {i+1} 和 {i+2} 重叠行数应该 >= {overlap},实际: {overlap_lines} ({description})"
340
+
341
+ # 验证覆盖完整性(所有行都被覆盖)
342
+ covered_lines = set()
343
+ for start_line, end_line, _ in chunks:
344
+ for line_num in range(start_line, end_line + 1):
345
+ covered_lines.add(line_num)
346
+
347
+ expected_lines = set(range(1, total_lines + 1))
348
+ assert covered_lines == expected_lines, f"应该覆盖所有行1-{total_lines} ({description})"
349
+
350
+ print(f" ✅ 验证通过: {len(chunks)} 个chunks,覆盖所有 {total_lines} 行")
351
+
352
+ # 追加基于math_utils_content的真实代码测试
353
+ print(f"\n🧮 测试真实代码内容 - math_utils.py")
354
+ math_utils_content = '''def add(a, b):
355
+ """加法函数"""
356
+ return a + b
357
+
358
+ def subtract(a, b):
359
+ """减法函数"""
360
+ return a - b
361
+
362
+ def multiply(a, b):
363
+ """乘法函数"""
364
+ return a * b
365
+
366
+ def divide(a, b):
367
+ """除法函数"""
368
+ if b == 0:
369
+ raise ValueError("Cannot divide by zero")
370
+ return a / b
371
+ '''
372
+
373
+ math_content_lines = math_utils_content.split('\n')
374
+ math_total_lines = len([line for line in math_content_lines if line.strip()]) # 只计算非空行
375
+ print(f"math_utils.py 总行数: {len(math_content_lines)} (非空行: {math_total_lines})")
376
+
377
+ # 测试适合代码的窗口配置
378
+ math_test_cases = [
379
+ {
380
+ "window_size": 4,
381
+ "overlap": 1,
382
+ "description": "小窗口配置适合函数分割"
383
+ },
384
+ {
385
+ "window_size": 6,
386
+ "overlap": 2,
387
+ "description": "中等窗口配置包含完整函数"
388
+ }
389
+ ]
390
+
391
+ for case in math_test_cases:
392
+ window_size = case["window_size"]
393
+ overlap = case["overlap"]
394
+ description = case["description"]
395
+
396
+ print(f"\n🔍 测试 {description}: 窗口={window_size}, 重叠={overlap}")
397
+
398
+ chunks = pruner._split_content_with_sliding_window(
399
+ content=math_utils_content,
400
+ window_size=window_size,
401
+ overlap=overlap
402
+ )
403
+
404
+ print(f" 生成 {len(chunks)} 个chunks:")
405
+
406
+ # 验证基本结构
407
+ assert isinstance(chunks, list), f"应该返回chunk列表 ({description})"
408
+ assert len(chunks) > 0, f"应该至少有一个chunk ({description})"
409
+
410
+ # 分析每个chunk的内容
411
+ function_keywords = ["def add(", "def subtract(", "def multiply(", "def divide("]
412
+
413
+ for i, chunk in enumerate(chunks):
414
+ start_line, end_line, chunk_content = chunk
415
+ print(f" Chunk {i+1}: 行 {start_line}-{end_line}")
416
+
417
+ # 检查这个chunk包含哪些函数定义
418
+ found_functions = []
419
+ for keyword in function_keywords:
420
+ if keyword in chunk_content:
421
+ func_name = keyword[4:-1] # 提取函数名 (去掉 "def " 和 "(")
422
+ found_functions.append(func_name)
423
+
424
+ if found_functions:
425
+ print(f" 包含函数: {', '.join(found_functions)}")
426
+ else:
427
+ print(f" 包含: 函数体或注释部分")
428
+
429
+ # 验证基本结构
430
+ assert isinstance(chunk, tuple), f"Chunk {i+1} 应该是元组 ({description})"
431
+ assert len(chunk) == 3, f"Chunk {i+1} 应该包含3个元素 ({description})"
432
+ assert isinstance(start_line, int), f"Chunk {i+1} 起始行号应该是整数 ({description})"
433
+ assert isinstance(end_line, int), f"Chunk {i+1} 结束行号应该是整数 ({description})"
434
+ assert isinstance(chunk_content, str), f"Chunk {i+1} 内容应该是字符串 ({description})"
435
+ assert len(chunk_content.strip()) > 0, f"Chunk {i+1} 内容不应为空 ({description})"
436
+
437
+ # 验证所有函数定义都被覆盖
438
+ all_chunk_content = "\n".join(chunk[2] for chunk in chunks)
439
+ for keyword in function_keywords:
440
+ assert keyword in all_chunk_content, f"应该覆盖函数定义: {keyword} ({description})"
441
+
442
+ print(f" ✅ 验证通过: 所有函数定义都被覆盖")
443
+
444
+ def test_merge_overlapping_snippets(self, pruner):
445
+ """测试重叠片段合并功能"""
446
+ # 测试重叠片段
447
+ snippets = [
448
+ {"start_line": 1, "end_line": 5},
449
+ {"start_line": 4, "end_line": 8},
450
+ {"start_line": 10, "end_line": 15}
451
+ ]
452
+
453
+ merged = pruner._merge_overlapping_snippets(snippets)
454
+
455
+ # 验证结果
456
+ assert isinstance(merged, list), "应该返回片段列表"
457
+ assert len(merged) == 2, "应该合并为2个片段"
458
+
459
+ # 验证合并结果
460
+ assert merged[0]["start_line"] == 1, "第一个片段起始行应该是1"
461
+ assert merged[0]["end_line"] == 8, "第一个片段结束行应该是8"
462
+ assert merged[1]["start_line"] == 10, "第二个片段起始行应该是10"
463
+ assert merged[1]["end_line"] == 15, "第二个片段结束行应该是15"
464
+
465
+ def test_build_snippet_content(self, pruner):
466
+ """测试构建片段内容功能"""
467
+ full_content = """def add(a, b):
468
+ return a + b
469
+
470
+ def subtract(a, b):
471
+ return a - b
472
+
473
+ def multiply(a, b):
474
+ return a * b"""
475
+
476
+ snippets = [
477
+ {"start_line": 1, "end_line": 2},
478
+ {"start_line": 4, "end_line": 5}
479
+ ]
480
+
481
+ result = pruner._build_snippet_content(
482
+ "test.py", full_content, snippets)
483
+
484
+ # 验证结果
485
+ assert isinstance(result, str), "应该返回字符串"
486
+ assert "Snippets:" in result, "应该包含Snippets标题"
487
+ assert "def add(a, b):" in result, "应该包含add函数"
488
+ assert "def subtract(a, b):" in result, "应该包含subtract函数"
489
+
490
+ def test_invalid_strategy(self, pruner, sample_file_sources, sample_conversations):
491
+ """测试无效策略处理"""
492
+ with pytest.raises(ValueError) as exc_info:
493
+ pruner.handle_overflow(
494
+ file_sources=sample_file_sources,
495
+ conversations=sample_conversations,
496
+ strategy="invalid_strategy"
497
+ )
498
+
499
+ assert "无效策略" in str(exc_info.value), "应该抛出无效策略错误"
500
+
501
+ def test_verbose_functionality(self, verbose_pruner, sample_file_sources, sample_conversations, capsys):
502
+ """测试verbose参数的功能"""
503
+ # 使用verbose=True的pruner进行测试
504
+ result = verbose_pruner.handle_overflow(
505
+ file_sources=sample_file_sources,
506
+ conversations=sample_conversations,
507
+ strategy="extract"
508
+ )
509
+
510
+ # 捕获输出
511
+ captured = capsys.readouterr()
512
+
513
+ # 验证verbose输出包含预期的信息
514
+ assert "🚀 开始代码片段抽取处理" in captured.out, "应该包含开始处理的信息"
515
+ assert "📋 处理策略" in captured.out, "应该包含处理策略信息"
516
+ assert "🎯 代码片段抽取处理完成" in captured.out, "应该包含处理完成的信息"
517
+ assert "📊 处理结果统计" in captured.out, "应该包含结果统计信息"
518
+
519
+ # 验证结果仍然正确
520
+ assert isinstance(result, list), "应该返回文件列表"
521
+ assert len(result) >= 0, "应该返回有效的结果列表"
522
+
523
+ def test_non_verbose_functionality(self, pruner, sample_file_sources, sample_conversations, capsys):
524
+ """测试verbose=False时不输出详细信息"""
525
+ # 使用verbose=False的pruner进行测试
526
+ result = pruner.handle_overflow(
527
+ file_sources=sample_file_sources,
528
+ conversations=sample_conversations,
529
+ strategy="extract"
530
+ )
531
+
532
+ # 捕获输出
533
+ captured = capsys.readouterr()
534
+
535
+ # 验证不包含verbose特有的输出
536
+ assert "🚀 开始代码片段抽取处理" not in captured.out, "非verbose模式不应该包含详细处理信息"
537
+ assert "📋 处理策略" not in captured.out, "非verbose模式不应该包含处理策略信息"
538
+ assert "🎯 代码片段抽取处理完成" not in captured.out, "非verbose模式不应该包含处理完成的详细信息"
539
+
540
+ # 验证结果仍然正确
541
+ assert isinstance(result, list), "应该返回文件列表"
542
+ assert len(result) >= 0, "应该返回有效的结果列表"
543
+
544
+
545
+ if __name__ == "__main__":
546
+ pytest.main([__file__, "-v"])