auto-coder 1.0.0__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 (574) 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-1.0.0.dist-info → auto_coder-2.0.0.dist-info}/WHEEL +1 -1
  5. {auto_coder-1.0.0.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 +24 -3
  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 +970 -2345
  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 +988 -398
  28. autocoder/chat_auto_coder_lang.py +23 -732
  29. autocoder/commands/auto_command.py +25 -8
  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/git_utils.py +44 -8
  119. autocoder/common/global_cancel.py +15 -6
  120. autocoder/common/ignorefiles/test_ignore_file_utils.py +1 -1
  121. autocoder/common/international/__init__.py +31 -0
  122. autocoder/common/international/demo_international.py +92 -0
  123. autocoder/common/international/message_manager.py +157 -0
  124. autocoder/common/international/messages/__init__.py +56 -0
  125. autocoder/common/international/messages/async_command_messages.py +507 -0
  126. autocoder/common/international/messages/auto_coder_messages.py +2208 -0
  127. autocoder/common/international/messages/chat_auto_coder_messages.py +1547 -0
  128. autocoder/common/international/messages/command_help_messages.py +986 -0
  129. autocoder/common/international/messages/conversation_command_messages.py +191 -0
  130. autocoder/common/international/messages/git_helper_plugin_messages.py +159 -0
  131. autocoder/common/international/messages/queue_command_messages.py +751 -0
  132. autocoder/common/international/messages/rules_command_messages.py +77 -0
  133. autocoder/common/international/messages/sdk_messages.py +1707 -0
  134. autocoder/common/international/messages/token_helper_plugin_messages.py +361 -0
  135. autocoder/common/international/messages/tool_display_messages.py +1212 -0
  136. autocoder/common/international/messages/workflow_exception_messages.py +473 -0
  137. autocoder/common/international/test_international.py +612 -0
  138. autocoder/common/linter_core/__init__.py +28 -0
  139. autocoder/common/linter_core/base_linter.py +61 -0
  140. autocoder/common/linter_core/config_loader.py +271 -0
  141. autocoder/common/linter_core/formatters/__init__.py +0 -0
  142. autocoder/common/linter_core/formatters/base_formatter.py +38 -0
  143. autocoder/common/linter_core/formatters/raw_formatter.py +17 -0
  144. autocoder/common/linter_core/linter.py +166 -0
  145. autocoder/common/linter_core/linter_factory.py +216 -0
  146. autocoder/common/linter_core/linter_manager.py +333 -0
  147. autocoder/common/linter_core/linters/__init__.py +9 -0
  148. autocoder/common/linter_core/linters/java_linter.py +342 -0
  149. autocoder/common/linter_core/linters/python_linter.py +115 -0
  150. autocoder/common/linter_core/linters/typescript_linter.py +119 -0
  151. autocoder/common/linter_core/models/__init__.py +7 -0
  152. autocoder/common/linter_core/models/lint_result.py +91 -0
  153. autocoder/common/linter_core/models.py +33 -0
  154. autocoder/common/linter_core/tests/__init__.py +3 -0
  155. autocoder/common/linter_core/tests/test_config_loader.py +323 -0
  156. autocoder/common/linter_core/tests/test_config_loading.py +308 -0
  157. autocoder/common/linter_core/tests/test_factory_manager.py +234 -0
  158. autocoder/common/linter_core/tests/test_formatters.py +147 -0
  159. autocoder/common/linter_core/tests/test_integration.py +317 -0
  160. autocoder/common/linter_core/tests/test_java_linter.py +496 -0
  161. autocoder/common/linter_core/tests/test_linters.py +265 -0
  162. autocoder/common/linter_core/tests/test_models.py +81 -0
  163. autocoder/common/linter_core/tests/verify_config_loading.py +296 -0
  164. autocoder/common/linter_core/tests/verify_fixes.py +183 -0
  165. autocoder/common/llm_friendly_package/__init__.py +31 -0
  166. autocoder/common/llm_friendly_package/base_manager.py +102 -0
  167. autocoder/common/llm_friendly_package/docs_manager.py +121 -0
  168. autocoder/common/llm_friendly_package/library_manager.py +171 -0
  169. autocoder/common/{llm_friendly_package.py → llm_friendly_package/main_manager.py} +204 -231
  170. autocoder/common/llm_friendly_package/models.py +40 -0
  171. autocoder/common/llm_friendly_package/test_llm_friendly_package.py +536 -0
  172. autocoder/common/llms/__init__.py +15 -0
  173. autocoder/common/llms/demo_error_handling.py +85 -0
  174. autocoder/common/llms/factory.py +142 -0
  175. autocoder/common/llms/manager.py +264 -0
  176. autocoder/common/llms/pricing.py +121 -0
  177. autocoder/common/llms/registry.py +288 -0
  178. autocoder/common/llms/schema.py +77 -0
  179. autocoder/common/llms/simple_demo.py +45 -0
  180. autocoder/common/llms/test_quick_model.py +116 -0
  181. autocoder/common/llms/test_remove_functionality.py +182 -0
  182. autocoder/common/llms/tests/__init__.py +1 -0
  183. autocoder/common/llms/tests/test_manager.py +330 -0
  184. autocoder/common/llms/tests/test_registry.py +364 -0
  185. autocoder/common/mcp_tools/__init__.py +62 -0
  186. autocoder/common/{mcp_tools.py → mcp_tools/executor.py} +49 -40
  187. autocoder/common/{mcp_hub.py → mcp_tools/hub.py} +42 -68
  188. autocoder/common/{mcp_server_install.py → mcp_tools/installer.py} +16 -28
  189. autocoder/common/{mcp_server.py → mcp_tools/server.py} +176 -48
  190. autocoder/common/mcp_tools/test_keyboard_interrupt.py +93 -0
  191. autocoder/common/mcp_tools/test_mcp_tools.py +391 -0
  192. autocoder/common/{mcp_server_types.py → mcp_tools/types.py} +121 -48
  193. autocoder/common/mcp_tools/verify_functionality.py +202 -0
  194. autocoder/common/model_speed_tester.py +32 -26
  195. autocoder/common/priority_directory_finder/__init__.py +142 -0
  196. autocoder/common/priority_directory_finder/examples.py +230 -0
  197. autocoder/common/priority_directory_finder/finder.py +283 -0
  198. autocoder/common/priority_directory_finder/models.py +236 -0
  199. autocoder/common/priority_directory_finder/test_priority_directory_finder.py +431 -0
  200. autocoder/common/project_scanner/__init__.py +18 -0
  201. autocoder/common/project_scanner/compat.py +77 -0
  202. autocoder/common/project_scanner/scanner.py +436 -0
  203. autocoder/common/project_tracker/__init__.py +27 -0
  204. autocoder/common/project_tracker/api.py +228 -0
  205. autocoder/common/project_tracker/demo.py +272 -0
  206. autocoder/common/project_tracker/tracker.py +487 -0
  207. autocoder/common/project_tracker/types.py +53 -0
  208. autocoder/common/pruner/__init__.py +67 -0
  209. autocoder/common/pruner/agentic_conversation_pruner.py +651 -102
  210. autocoder/common/pruner/conversation_message_ids_api.py +386 -0
  211. autocoder/common/pruner/conversation_message_ids_manager.py +347 -0
  212. autocoder/common/pruner/conversation_message_ids_pruner.py +473 -0
  213. autocoder/common/pruner/conversation_normalizer.py +347 -0
  214. autocoder/common/pruner/conversation_pruner.py +26 -6
  215. autocoder/common/pruner/test_agentic_conversation_pruner.py +554 -112
  216. autocoder/common/pruner/test_conversation_normalizer.py +502 -0
  217. autocoder/common/pruner/test_tool_content_detector.py +324 -0
  218. autocoder/common/pruner/tool_content_detector.py +227 -0
  219. autocoder/common/pruner/tools/__init__.py +18 -0
  220. autocoder/common/pruner/tools/query_message_ids.py +264 -0
  221. autocoder/common/pruner/tools/test_agentic_pruning_logic.py +432 -0
  222. autocoder/common/pruner/tools/test_message_ids_pruning_only.py +192 -0
  223. autocoder/common/pull_requests/__init__.py +9 -1
  224. autocoder/common/pull_requests/utils.py +122 -1
  225. autocoder/common/rag_manager/rag_manager.py +36 -40
  226. autocoder/common/rulefiles/__init__.py +53 -1
  227. autocoder/common/rulefiles/api.py +250 -0
  228. autocoder/common/rulefiles/core/__init__.py +14 -0
  229. autocoder/common/rulefiles/core/manager.py +241 -0
  230. autocoder/common/rulefiles/core/selector.py +805 -0
  231. autocoder/common/rulefiles/models/__init__.py +20 -0
  232. autocoder/common/rulefiles/models/index.py +16 -0
  233. autocoder/common/rulefiles/models/init_rule.py +18 -0
  234. autocoder/common/rulefiles/models/rule_file.py +18 -0
  235. autocoder/common/rulefiles/models/rule_relevance.py +14 -0
  236. autocoder/common/rulefiles/models/summary.py +16 -0
  237. autocoder/common/rulefiles/test_rulefiles.py +776 -0
  238. autocoder/common/rulefiles/utils/__init__.py +34 -0
  239. autocoder/common/rulefiles/utils/monitor.py +86 -0
  240. autocoder/common/rulefiles/utils/parser.py +230 -0
  241. autocoder/common/save_formatted_log.py +67 -10
  242. autocoder/common/search_replace.py +8 -1
  243. autocoder/common/search_replace_patch/__init__.py +24 -0
  244. autocoder/common/search_replace_patch/base.py +115 -0
  245. autocoder/common/search_replace_patch/manager.py +248 -0
  246. autocoder/common/search_replace_patch/patch_replacer.py +304 -0
  247. autocoder/common/search_replace_patch/similarity_replacer.py +306 -0
  248. autocoder/common/search_replace_patch/string_replacer.py +181 -0
  249. autocoder/common/search_replace_patch/tests/__init__.py +3 -0
  250. autocoder/common/search_replace_patch/tests/run_tests.py +126 -0
  251. autocoder/common/search_replace_patch/tests/test_base.py +188 -0
  252. autocoder/common/search_replace_patch/tests/test_empty_line_insert.py +233 -0
  253. autocoder/common/search_replace_patch/tests/test_integration.py +389 -0
  254. autocoder/common/search_replace_patch/tests/test_manager.py +351 -0
  255. autocoder/common/search_replace_patch/tests/test_patch_replacer.py +316 -0
  256. autocoder/common/search_replace_patch/tests/test_regex_replacer.py +306 -0
  257. autocoder/common/search_replace_patch/tests/test_similarity_replacer.py +384 -0
  258. autocoder/common/shell_commands/__init__.py +197 -0
  259. autocoder/common/shell_commands/background_process_notifier.py +346 -0
  260. autocoder/common/shell_commands/command_executor.py +1127 -0
  261. autocoder/common/shell_commands/error_recovery.py +541 -0
  262. autocoder/common/shell_commands/exceptions.py +120 -0
  263. autocoder/common/shell_commands/interactive_executor.py +476 -0
  264. autocoder/common/shell_commands/interactive_pexpect_process.py +623 -0
  265. autocoder/common/shell_commands/interactive_process.py +744 -0
  266. autocoder/common/shell_commands/interactive_session_manager.py +1014 -0
  267. autocoder/common/shell_commands/monitoring.py +529 -0
  268. autocoder/common/shell_commands/process_cleanup.py +386 -0
  269. autocoder/common/shell_commands/process_manager.py +606 -0
  270. autocoder/common/shell_commands/test_interactive_pexpect_process.py +281 -0
  271. autocoder/common/shell_commands/tests/__init__.py +6 -0
  272. autocoder/common/shell_commands/tests/conftest.py +118 -0
  273. autocoder/common/shell_commands/tests/test_background_process_notifier.py +703 -0
  274. autocoder/common/shell_commands/tests/test_command_executor.py +448 -0
  275. autocoder/common/shell_commands/tests/test_error_recovery.py +305 -0
  276. autocoder/common/shell_commands/tests/test_exceptions.py +299 -0
  277. autocoder/common/shell_commands/tests/test_execute_batch.py +588 -0
  278. autocoder/common/shell_commands/tests/test_indented_batch_commands.py +244 -0
  279. autocoder/common/shell_commands/tests/test_integration.py +664 -0
  280. autocoder/common/shell_commands/tests/test_monitoring.py +546 -0
  281. autocoder/common/shell_commands/tests/test_performance.py +632 -0
  282. autocoder/common/shell_commands/tests/test_process_cleanup.py +397 -0
  283. autocoder/common/shell_commands/tests/test_process_manager.py +606 -0
  284. autocoder/common/shell_commands/tests/test_timeout_config.py +343 -0
  285. autocoder/common/shell_commands/tests/test_timeout_manager.py +520 -0
  286. autocoder/common/shell_commands/timeout_config.py +315 -0
  287. autocoder/common/shell_commands/timeout_manager.py +352 -0
  288. autocoder/common/terminal_paste/__init__.py +14 -0
  289. autocoder/common/terminal_paste/demo.py +145 -0
  290. autocoder/common/terminal_paste/demo_paste_functionality.py +95 -0
  291. autocoder/common/terminal_paste/paste_handler.py +200 -0
  292. autocoder/common/terminal_paste/paste_manager.py +118 -0
  293. autocoder/common/terminal_paste/tests/__init__.py +1 -0
  294. autocoder/common/terminal_paste/tests/test_paste_handler.py +182 -0
  295. autocoder/common/terminal_paste/tests/test_paste_manager.py +126 -0
  296. autocoder/common/terminal_paste/utils.py +163 -0
  297. autocoder/common/test_autocoder_args.py +232 -0
  298. autocoder/common/test_env_manager.py +173 -0
  299. autocoder/common/test_env_manager_integration.py +159 -0
  300. autocoder/common/text_similarity/__init__.py +9 -0
  301. autocoder/common/text_similarity/demo.py +216 -0
  302. autocoder/common/text_similarity/examples.py +266 -0
  303. autocoder/common/text_similarity/test_text_similarity.py +306 -0
  304. autocoder/common/text_similarity/text_similarity.py +194 -0
  305. autocoder/common/text_similarity/utils.py +125 -0
  306. autocoder/common/todos/__init__.py +61 -0
  307. autocoder/common/todos/cache/__init__.py +16 -0
  308. autocoder/common/todos/cache/base_cache.py +89 -0
  309. autocoder/common/todos/cache/cache_manager.py +228 -0
  310. autocoder/common/todos/cache/memory_cache.py +225 -0
  311. autocoder/common/todos/config.py +155 -0
  312. autocoder/common/todos/exceptions.py +35 -0
  313. autocoder/common/todos/get_todo_manager.py +161 -0
  314. autocoder/common/todos/manager.py +537 -0
  315. autocoder/common/todos/models.py +239 -0
  316. autocoder/common/todos/storage/__init__.py +14 -0
  317. autocoder/common/todos/storage/base_storage.py +76 -0
  318. autocoder/common/todos/storage/file_storage.py +278 -0
  319. autocoder/common/tokens/counter.py +24 -2
  320. autocoder/common/tools_manager/__init__.py +17 -0
  321. autocoder/common/tools_manager/examples.py +162 -0
  322. autocoder/common/tools_manager/manager.py +385 -0
  323. autocoder/common/tools_manager/models.py +39 -0
  324. autocoder/common/tools_manager/test_tools_manager.py +303 -0
  325. autocoder/common/tools_manager/utils.py +191 -0
  326. autocoder/common/v2/agent/agentic_callbacks.py +270 -0
  327. autocoder/common/v2/agent/agentic_edit.py +2699 -1856
  328. autocoder/common/v2/agent/agentic_edit_change_manager.py +474 -0
  329. autocoder/common/v2/agent/agentic_edit_tools/__init__.py +35 -1
  330. autocoder/common/v2/agent/agentic_edit_tools/ac_mod_list_tool_resolver.py +279 -0
  331. autocoder/common/v2/agent/agentic_edit_tools/ac_mod_write_tool_resolver.py +10 -1
  332. autocoder/common/v2/agent/agentic_edit_tools/background_task_tool_resolver.py +1167 -0
  333. autocoder/common/v2/agent/agentic_edit_tools/base_tool_resolver.py +2 -2
  334. autocoder/common/v2/agent/agentic_edit_tools/conversation_message_ids_read_tool_resolver.py +214 -0
  335. autocoder/common/v2/agent/agentic_edit_tools/conversation_message_ids_write_tool_resolver.py +299 -0
  336. autocoder/common/v2/agent/agentic_edit_tools/count_tokens_tool_resolver.py +290 -0
  337. autocoder/common/v2/agent/agentic_edit_tools/execute_command_tool_resolver.py +564 -29
  338. autocoder/common/v2/agent/agentic_edit_tools/execute_workflow_tool_resolver.py +485 -0
  339. autocoder/common/v2/agent/agentic_edit_tools/extract_to_text_tool_resolver.py +225 -0
  340. autocoder/common/v2/agent/agentic_edit_tools/lint_report.py +79 -0
  341. autocoder/common/v2/agent/agentic_edit_tools/linter_config_models.py +343 -0
  342. autocoder/common/v2/agent/agentic_edit_tools/linter_enabled_tool_resolver.py +189 -0
  343. autocoder/common/v2/agent/agentic_edit_tools/list_files_tool_resolver.py +169 -101
  344. autocoder/common/v2/agent/agentic_edit_tools/load_extra_document_tool_resolver.py +349 -0
  345. autocoder/common/v2/agent/agentic_edit_tools/read_file_tool_resolver.py +243 -50
  346. autocoder/common/v2/agent/agentic_edit_tools/replace_in_file_tool_resolver.py +667 -147
  347. autocoder/common/v2/agent/agentic_edit_tools/run_named_subagents_tool_resolver.py +691 -0
  348. autocoder/common/v2/agent/agentic_edit_tools/search_files_tool_resolver.py +410 -86
  349. autocoder/common/v2/agent/agentic_edit_tools/session_interactive_tool_resolver.py +115 -0
  350. autocoder/common/v2/agent/agentic_edit_tools/session_start_tool_resolver.py +190 -0
  351. autocoder/common/v2/agent/agentic_edit_tools/session_stop_tool_resolver.py +76 -0
  352. autocoder/common/v2/agent/agentic_edit_tools/test_write_to_file_tool_resolver.py +207 -192
  353. autocoder/common/v2/agent/agentic_edit_tools/todo_read_tool_resolver.py +80 -63
  354. autocoder/common/v2/agent/agentic_edit_tools/todo_write_tool_resolver.py +237 -233
  355. autocoder/common/v2/agent/agentic_edit_tools/use_mcp_tool_resolver.py +2 -2
  356. autocoder/common/v2/agent/agentic_edit_tools/web_crawl_tool_resolver.py +557 -0
  357. autocoder/common/v2/agent/agentic_edit_tools/web_search_tool_resolver.py +600 -0
  358. autocoder/common/v2/agent/agentic_edit_tools/write_to_file_tool_resolver.py +56 -121
  359. autocoder/common/v2/agent/agentic_edit_types.py +343 -9
  360. autocoder/common/v2/agent/runner/__init__.py +3 -3
  361. autocoder/common/v2/agent/runner/base_runner.py +12 -26
  362. autocoder/common/v2/agent/runner/{event_runner.py → file_based_event_runner.py} +3 -2
  363. autocoder/common/v2/agent/runner/sdk_runner.py +150 -8
  364. autocoder/common/v2/agent/runner/terminal_runner.py +170 -57
  365. autocoder/common/v2/agent/runner/tool_display.py +557 -159
  366. autocoder/common/v2/agent/test_agentic_callbacks.py +265 -0
  367. autocoder/common/v2/agent/test_agentic_edit.py +194 -0
  368. autocoder/common/v2/agent/tool_caller/__init__.py +24 -0
  369. autocoder/common/v2/agent/tool_caller/default_tool_resolver_map.py +135 -0
  370. autocoder/common/v2/agent/tool_caller/integration_test.py +172 -0
  371. autocoder/common/v2/agent/tool_caller/plugins/__init__.py +14 -0
  372. autocoder/common/v2/agent/tool_caller/plugins/base_plugin.py +126 -0
  373. autocoder/common/v2/agent/tool_caller/plugins/examples/__init__.py +13 -0
  374. autocoder/common/v2/agent/tool_caller/plugins/examples/logging_plugin.py +164 -0
  375. autocoder/common/v2/agent/tool_caller/plugins/examples/security_filter_plugin.py +198 -0
  376. autocoder/common/v2/agent/tool_caller/plugins/plugin_interface.py +141 -0
  377. autocoder/common/v2/agent/tool_caller/test_tool_caller.py +278 -0
  378. autocoder/common/v2/agent/tool_caller/tool_call_plugin_manager.py +331 -0
  379. autocoder/common/v2/agent/tool_caller/tool_caller.py +337 -0
  380. autocoder/common/v2/agent/tool_caller/usage_example.py +193 -0
  381. autocoder/common/v2/code_agentic_editblock_manager.py +4 -4
  382. autocoder/common/v2/code_auto_generate.py +136 -78
  383. autocoder/common/v2/code_auto_generate_diff.py +135 -79
  384. autocoder/common/v2/code_auto_generate_editblock.py +174 -99
  385. autocoder/common/v2/code_auto_generate_strict_diff.py +151 -71
  386. autocoder/common/v2/code_auto_merge.py +1 -1
  387. autocoder/common/v2/code_auto_merge_editblock.py +13 -1
  388. autocoder/common/v2/code_diff_manager.py +3 -3
  389. autocoder/common/v2/code_editblock_manager.py +4 -14
  390. autocoder/common/v2/code_manager.py +1 -1
  391. autocoder/common/v2/code_strict_diff_manager.py +2 -2
  392. autocoder/common/wrap_llm_hint/__init__.py +10 -0
  393. autocoder/common/wrap_llm_hint/test_wrap_llm_hint.py +1067 -0
  394. autocoder/common/wrap_llm_hint/utils.py +432 -0
  395. autocoder/common/wrap_llm_hint/wrap_llm_hint.py +323 -0
  396. autocoder/completer/__init__.py +8 -0
  397. autocoder/completer/command_completer_v2.py +1051 -0
  398. autocoder/default_project/__init__.py +501 -0
  399. autocoder/dispacher/__init__.py +4 -12
  400. autocoder/dispacher/actions/action.py +165 -7
  401. autocoder/dispacher/actions/plugins/action_regex_project.py +2 -2
  402. autocoder/index/entry.py +116 -124
  403. autocoder/{agent → index/filter}/agentic_filter.py +322 -333
  404. autocoder/index/filter/normal_filter.py +5 -11
  405. autocoder/index/filter/quick_filter.py +1 -1
  406. autocoder/index/index.py +36 -9
  407. autocoder/index/tests/__init__.py +1 -0
  408. autocoder/index/tests/run_tests.py +195 -0
  409. autocoder/index/tests/test_entry.py +303 -0
  410. autocoder/index/tests/test_index_manager.py +314 -0
  411. autocoder/index/tests/test_module_integration.py +300 -0
  412. autocoder/index/tests/test_symbols_utils.py +183 -0
  413. autocoder/inner/__init__.py +4 -0
  414. autocoder/inner/agentic.py +932 -0
  415. autocoder/inner/async_command_handler.py +992 -0
  416. autocoder/inner/conversation_command_handlers.py +623 -0
  417. autocoder/inner/merge_command_handler.py +213 -0
  418. autocoder/inner/queue_command_handler.py +684 -0
  419. autocoder/models.py +95 -266
  420. autocoder/plugins/git_helper_plugin.py +31 -29
  421. autocoder/plugins/token_helper_plugin.py +65 -46
  422. autocoder/pyproject/__init__.py +32 -29
  423. autocoder/rag/agentic_rag.py +215 -75
  424. autocoder/rag/cache/simple_cache.py +1 -2
  425. autocoder/rag/loaders/image_loader.py +1 -1
  426. autocoder/rag/long_context_rag.py +42 -26
  427. autocoder/rag/qa_conversation_strategy.py +1 -1
  428. autocoder/rag/terminal/__init__.py +17 -0
  429. autocoder/rag/terminal/args.py +581 -0
  430. autocoder/rag/terminal/bootstrap.py +61 -0
  431. autocoder/rag/terminal/command_handlers.py +653 -0
  432. autocoder/rag/terminal/formatters/__init__.py +20 -0
  433. autocoder/rag/terminal/formatters/base.py +70 -0
  434. autocoder/rag/terminal/formatters/json_format.py +66 -0
  435. autocoder/rag/terminal/formatters/stream_json.py +95 -0
  436. autocoder/rag/terminal/formatters/text.py +28 -0
  437. autocoder/rag/terminal/init.py +120 -0
  438. autocoder/rag/terminal/utils.py +106 -0
  439. autocoder/rag/test_agentic_rag.py +389 -0
  440. autocoder/rag/test_doc_filter.py +3 -3
  441. autocoder/rag/test_long_context_rag.py +1 -1
  442. autocoder/rag/test_token_limiter.py +517 -10
  443. autocoder/rag/token_counter.py +3 -0
  444. autocoder/rag/token_limiter.py +19 -15
  445. autocoder/rag/tools/__init__.py +26 -2
  446. autocoder/rag/tools/bochaai_example.py +343 -0
  447. autocoder/rag/tools/bochaai_sdk.py +541 -0
  448. autocoder/rag/tools/metaso_example.py +268 -0
  449. autocoder/rag/tools/metaso_sdk.py +417 -0
  450. autocoder/rag/tools/recall_tool.py +28 -7
  451. autocoder/rag/tools/run_integration_tests.py +204 -0
  452. autocoder/rag/tools/test_all_providers.py +318 -0
  453. autocoder/rag/tools/test_bochaai_integration.py +482 -0
  454. autocoder/rag/tools/test_final_integration.py +215 -0
  455. autocoder/rag/tools/test_metaso_integration.py +424 -0
  456. autocoder/rag/tools/test_metaso_real.py +171 -0
  457. autocoder/rag/tools/test_web_crawl_tool.py +639 -0
  458. autocoder/rag/tools/test_web_search_tool.py +509 -0
  459. autocoder/rag/tools/todo_read_tool.py +202 -0
  460. autocoder/rag/tools/todo_write_tool.py +412 -0
  461. autocoder/rag/tools/web_crawl_tool.py +634 -0
  462. autocoder/rag/tools/web_search_tool.py +558 -0
  463. autocoder/rag/tools/web_tools_example.py +119 -0
  464. autocoder/rag/types.py +16 -0
  465. autocoder/rag/variable_holder.py +4 -2
  466. autocoder/rags.py +86 -79
  467. autocoder/regexproject/__init__.py +23 -21
  468. autocoder/sdk/__init__.py +46 -190
  469. autocoder/sdk/api.py +370 -0
  470. autocoder/sdk/async_runner/__init__.py +26 -0
  471. autocoder/sdk/async_runner/async_executor.py +650 -0
  472. autocoder/sdk/async_runner/async_handler.py +356 -0
  473. autocoder/sdk/async_runner/markdown_processor.py +595 -0
  474. autocoder/sdk/async_runner/task_metadata.py +284 -0
  475. autocoder/sdk/async_runner/worktree_manager.py +438 -0
  476. autocoder/sdk/cli/__init__.py +2 -5
  477. autocoder/sdk/cli/formatters.py +28 -204
  478. autocoder/sdk/cli/handlers.py +77 -44
  479. autocoder/sdk/cli/main.py +154 -171
  480. autocoder/sdk/cli/options.py +95 -22
  481. autocoder/sdk/constants.py +139 -51
  482. autocoder/sdk/core/auto_coder_core.py +484 -109
  483. autocoder/sdk/core/bridge.py +297 -115
  484. autocoder/sdk/exceptions.py +18 -12
  485. autocoder/sdk/formatters/__init__.py +19 -0
  486. autocoder/sdk/formatters/input.py +64 -0
  487. autocoder/sdk/formatters/output.py +247 -0
  488. autocoder/sdk/formatters/stream.py +54 -0
  489. autocoder/sdk/models/__init__.py +6 -5
  490. autocoder/sdk/models/options.py +55 -18
  491. autocoder/sdk/utils/formatters.py +27 -195
  492. autocoder/suffixproject/__init__.py +28 -25
  493. autocoder/terminal/__init__.py +14 -0
  494. autocoder/terminal/app.py +454 -0
  495. autocoder/terminal/args.py +32 -0
  496. autocoder/terminal/bootstrap.py +178 -0
  497. autocoder/terminal/command_processor.py +521 -0
  498. autocoder/terminal/command_registry.py +57 -0
  499. autocoder/terminal/help.py +97 -0
  500. autocoder/terminal/tasks/__init__.py +5 -0
  501. autocoder/terminal/tasks/background.py +77 -0
  502. autocoder/terminal/tasks/task_event.py +70 -0
  503. autocoder/terminal/ui/__init__.py +13 -0
  504. autocoder/terminal/ui/completer.py +268 -0
  505. autocoder/terminal/ui/keybindings.py +75 -0
  506. autocoder/terminal/ui/session.py +41 -0
  507. autocoder/terminal/ui/toolbar.py +64 -0
  508. autocoder/terminal/utils/__init__.py +13 -0
  509. autocoder/terminal/utils/errors.py +18 -0
  510. autocoder/terminal/utils/paths.py +19 -0
  511. autocoder/terminal/utils/shell.py +43 -0
  512. autocoder/terminal_v3/__init__.py +10 -0
  513. autocoder/terminal_v3/app.py +201 -0
  514. autocoder/terminal_v3/handlers/__init__.py +5 -0
  515. autocoder/terminal_v3/handlers/command_handler.py +131 -0
  516. autocoder/terminal_v3/models/__init__.py +6 -0
  517. autocoder/terminal_v3/models/conversation_buffer.py +214 -0
  518. autocoder/terminal_v3/models/message.py +50 -0
  519. autocoder/terminal_v3/models/tool_display.py +247 -0
  520. autocoder/terminal_v3/ui/__init__.py +7 -0
  521. autocoder/terminal_v3/ui/keybindings.py +56 -0
  522. autocoder/terminal_v3/ui/layout.py +141 -0
  523. autocoder/terminal_v3/ui/styles.py +43 -0
  524. autocoder/tsproject/__init__.py +23 -23
  525. autocoder/utils/auto_coder_utils/chat_stream_out.py +1 -1
  526. autocoder/utils/llms.py +88 -80
  527. autocoder/utils/math_utils.py +101 -0
  528. autocoder/utils/model_provider_selector.py +16 -4
  529. autocoder/utils/operate_config_api.py +33 -5
  530. autocoder/utils/thread_utils.py +2 -2
  531. autocoder/version.py +4 -2
  532. autocoder/workflow_agents/__init__.py +84 -0
  533. autocoder/workflow_agents/agent.py +143 -0
  534. autocoder/workflow_agents/exceptions.py +573 -0
  535. autocoder/workflow_agents/executor.py +489 -0
  536. autocoder/workflow_agents/loader.py +737 -0
  537. autocoder/workflow_agents/runner.py +267 -0
  538. autocoder/workflow_agents/types.py +172 -0
  539. autocoder/workflow_agents/utils.py +434 -0
  540. autocoder/workflow_agents/workflow_manager.py +211 -0
  541. auto_coder-1.0.0.dist-info/METADATA +0 -396
  542. auto_coder-1.0.0.dist-info/RECORD +0 -442
  543. auto_coder-1.0.0.dist-info/licenses/LICENSE +0 -201
  544. autocoder/auto_coder_server.py +0 -672
  545. autocoder/benchmark.py +0 -138
  546. autocoder/common/ac_style_command_parser/example.py +0 -7
  547. autocoder/common/cleaner.py +0 -31
  548. autocoder/common/command_completer_v2.py +0 -615
  549. autocoder/common/context_pruner.py +0 -477
  550. autocoder/common/conversation_pruner.py +0 -132
  551. autocoder/common/directory_cache/__init__.py +0 -1
  552. autocoder/common/directory_cache/cache.py +0 -192
  553. autocoder/common/directory_cache/test_cache.py +0 -190
  554. autocoder/common/file_checkpoint/examples.py +0 -217
  555. autocoder/common/llm_friendly_package_example.py +0 -138
  556. autocoder/common/llm_friendly_package_test.py +0 -63
  557. autocoder/common/pull_requests/test_module.py +0 -1
  558. autocoder/common/rulefiles/autocoderrules_utils.py +0 -484
  559. autocoder/common/text.py +0 -30
  560. autocoder/common/v2/agent/agentic_edit_tools/list_package_info_tool_resolver.py +0 -42
  561. autocoder/common/v2/agent/agentic_edit_tools/test_execute_command_tool_resolver.py +0 -70
  562. autocoder/common/v2/agent/agentic_edit_tools/test_search_files_tool_resolver.py +0 -163
  563. autocoder/common/v2/agent/agentic_tool_display.py +0 -183
  564. autocoder/plugins/dynamic_completion_example.py +0 -148
  565. autocoder/plugins/sample_plugin.py +0 -160
  566. autocoder/sdk/cli/__main__.py +0 -26
  567. autocoder/sdk/cli/completion_wrapper.py +0 -38
  568. autocoder/sdk/cli/install_completion.py +0 -301
  569. autocoder/sdk/models/messages.py +0 -209
  570. autocoder/sdk/session/__init__.py +0 -32
  571. autocoder/sdk/session/session.py +0 -106
  572. autocoder/sdk/session/session_manager.py +0 -56
  573. {auto_coder-1.0.0.dist-info → auto_coder-2.0.0.dist-info}/top_level.txt +0 -0
  574. /autocoder/{sdk/example.py → common/agent_query_queue/__init__.py} +0 -0
@@ -0,0 +1,351 @@
1
+ """
2
+ Test module for SearchReplaceManager
3
+ """
4
+
5
+ import unittest
6
+ from unittest.mock import patch, MagicMock
7
+
8
+ from ..manager import SearchReplaceManager
9
+ from ..base import ReplaceStrategy, ReplaceResult
10
+ from ..string_replacer import StringReplacer
11
+ from ..patch_replacer import PatchReplacer
12
+ from ..similarity_replacer import SimilarityReplacer
13
+
14
+
15
+ class TestSearchReplaceManager(unittest.TestCase):
16
+ """Test SearchReplaceManager functionality"""
17
+
18
+ def setUp(self):
19
+ """Set up test fixtures"""
20
+ self.manager = SearchReplaceManager()
21
+ self.custom_manager = SearchReplaceManager(default_strategy=ReplaceStrategy.SIMILARITY)
22
+
23
+ def test_initialization(self):
24
+ """Test proper initialization"""
25
+ self.assertEqual(self.manager.default_strategy, ReplaceStrategy.STRING)
26
+ self.assertEqual(self.custom_manager.default_strategy, ReplaceStrategy.SIMILARITY)
27
+
28
+ # Check that replacers are initialized
29
+ self.assertIsInstance(self.manager.replacers.get(ReplaceStrategy.STRING), StringReplacer)
30
+
31
+ def test_get_replacer(self):
32
+ """Test getting replacer by strategy"""
33
+ string_replacer = self.manager.get_replacer(ReplaceStrategy.STRING)
34
+ self.assertIsInstance(string_replacer, StringReplacer)
35
+
36
+ similarity_replacer = self.manager.get_replacer(ReplaceStrategy.SIMILARITY)
37
+ self.assertIsInstance(similarity_replacer, SimilarityReplacer)
38
+
39
+ # Test non-existent strategy
40
+ non_existent = self.manager.get_replacer(ReplaceStrategy.PATCH)
41
+ if non_existent:
42
+ self.assertIsInstance(non_existent, PatchReplacer)
43
+
44
+ def test_replace_with_default_strategy(self):
45
+ """Test replace using default strategy"""
46
+ content = "Hello world\n"
47
+ search_blocks = [("Hello world", "Hello AutoCoder")]
48
+
49
+ with patch.object(self.manager.replacers[ReplaceStrategy.STRING], 'replace') as mock_replace:
50
+ mock_replace.return_value = ReplaceResult(success=True, message="Success", new_content="Hello AutoCoder\n")
51
+
52
+ result = self.manager.replace(content, search_blocks)
53
+
54
+ self.assertTrue(result.success)
55
+ self.assertEqual(result.new_content, "Hello AutoCoder\n")
56
+ mock_replace.assert_called_once_with(content, search_blocks)
57
+
58
+ def test_replace_with_specified_strategy(self):
59
+ """Test replace using specified strategy"""
60
+ content = "Hello world\n"
61
+ search_blocks = [("Hello world", "Hello AutoCoder")]
62
+
63
+ with patch.object(self.manager.replacers[ReplaceStrategy.SIMILARITY], 'replace') as mock_replace:
64
+ mock_replace.return_value = ReplaceResult(success=True, message="Success", new_content="Hello AutoCoder\n")
65
+
66
+ result = self.manager.replace(content, search_blocks, ReplaceStrategy.SIMILARITY)
67
+
68
+ self.assertTrue(result.success)
69
+ self.assertEqual(result.new_content, "Hello AutoCoder\n")
70
+ mock_replace.assert_called_once_with(content, search_blocks)
71
+
72
+ def test_replace_with_unavailable_strategy(self):
73
+ """Test replace with unavailable strategy"""
74
+ content = "Hello world"
75
+ search_blocks = [("world", "AutoCoder")]
76
+
77
+ # Mock strategy not available
78
+ with patch.object(self.manager, 'get_replacer', return_value=None):
79
+ result = self.manager.replace(content, search_blocks, ReplaceStrategy.PATCH)
80
+
81
+ self.assertFalse(result.success)
82
+ self.assertIn("not available", result.message)
83
+
84
+ def test_replace_with_fallback_first_success(self):
85
+ """Test fallback strategy when first strategy succeeds"""
86
+ content = "Hello world"
87
+ search_blocks = [("world", "AutoCoder")]
88
+
89
+ with patch.object(self.manager.replacers[ReplaceStrategy.STRING], 'replace') as mock_regex_replace:
90
+ mock_regex_replace.return_value = ReplaceResult(success=True, message="Success", new_content="Hello AutoCoder")
91
+
92
+ with patch.object(self.manager.replacers[ReplaceStrategy.STRING], 'can_handle', return_value=True):
93
+ result = self.manager.replace_with_fallback(content, search_blocks)
94
+
95
+ self.assertTrue(result.success)
96
+ self.assertEqual(result.new_content, "Hello AutoCoder")
97
+ self.assertEqual(result.metadata['used_strategy'], 'string')
98
+ mock_regex_replace.assert_called_once()
99
+
100
+ def test_replace_with_fallback_second_success(self):
101
+ """Test fallback strategy when first fails, second succeeds"""
102
+ content = "Hello world"
103
+ search_blocks = [("world", "AutoCoder")]
104
+
105
+ # First strategy fails
106
+ with patch.object(self.manager.replacers[ReplaceStrategy.STRING], 'replace') as mock_regex_replace:
107
+ mock_regex_replace.return_value = ReplaceResult(success=False, message="Failed")
108
+
109
+ with patch.object(self.manager.replacers[ReplaceStrategy.STRING], 'can_handle', return_value=True):
110
+ # Second strategy succeeds
111
+ with patch.object(self.manager.replacers[ReplaceStrategy.SIMILARITY], 'replace') as mock_similarity_replace:
112
+ mock_similarity_replace.return_value = ReplaceResult(success=True, message="Success", new_content="Hello AutoCoder")
113
+
114
+ with patch.object(self.manager.replacers[ReplaceStrategy.SIMILARITY], 'can_handle', return_value=True):
115
+ result = self.manager.replace_with_fallback(content, search_blocks)
116
+
117
+ self.assertTrue(result.success)
118
+ self.assertEqual(result.new_content, "Hello AutoCoder")
119
+ self.assertEqual(result.metadata['used_strategy'], 'similarity')
120
+ mock_regex_replace.assert_called_once()
121
+ mock_similarity_replace.assert_called_once()
122
+
123
+ def test_replace_with_fallback_all_fail(self):
124
+ """Test fallback strategy when all strategies fail"""
125
+ content = "Hello world"
126
+ search_blocks = [("world", "AutoCoder")]
127
+
128
+ # All strategies fail
129
+ with patch.object(self.manager.replacers[ReplaceStrategy.STRING], 'replace') as mock_regex_replace:
130
+ mock_regex_replace.return_value = ReplaceResult(success=False, message="Failed")
131
+
132
+ with patch.object(self.manager.replacers[ReplaceStrategy.STRING], 'can_handle', return_value=True):
133
+ with patch.object(self.manager.replacers[ReplaceStrategy.SIMILARITY], 'replace') as mock_similarity_replace:
134
+ mock_similarity_replace.return_value = ReplaceResult(success=False, message="Failed")
135
+
136
+ with patch.object(self.manager.replacers[ReplaceStrategy.SIMILARITY], 'can_handle', return_value=True):
137
+ result = self.manager.replace_with_fallback(content, search_blocks)
138
+
139
+ self.assertFalse(result.success)
140
+ self.assertIn('all_strategies_failed', result.metadata)
141
+ self.assertIn('tried_strategies', result.metadata)
142
+
143
+ def test_replace_with_fallback_custom_strategies(self):
144
+ """Test fallback with custom strategy list"""
145
+ content = "Hello world"
146
+ search_blocks = [("world", "AutoCoder")]
147
+ strategies = [ReplaceStrategy.SIMILARITY, ReplaceStrategy.STRING]
148
+
149
+ with patch.object(self.manager.replacers[ReplaceStrategy.SIMILARITY], 'replace') as mock_similarity_replace:
150
+ mock_similarity_replace.return_value = ReplaceResult(success=True, message="Success", new_content="Hello AutoCoder")
151
+
152
+ with patch.object(self.manager.replacers[ReplaceStrategy.SIMILARITY], 'can_handle', return_value=True):
153
+ result = self.manager.replace_with_fallback(content, search_blocks, strategies)
154
+
155
+ self.assertTrue(result.success)
156
+ self.assertEqual(result.metadata['used_strategy'], 'similarity')
157
+ mock_similarity_replace.assert_called_once()
158
+
159
+ def test_replace_with_fallback_no_suitable_replacer(self):
160
+ """Test fallback when no suitable replacer is found"""
161
+ content = "Hello world"
162
+ search_blocks = [("world", "AutoCoder")]
163
+
164
+ with patch.object(self.manager, 'get_replacer', return_value=None):
165
+ result = self.manager.replace_with_fallback(content, search_blocks)
166
+
167
+ self.assertFalse(result.success)
168
+ self.assertIn("No suitable replacer found", result.message)
169
+
170
+ def test_replace_with_fallback_replacer_cannot_handle(self):
171
+ """Test fallback when replacer cannot handle content"""
172
+ content = "Hello world"
173
+ search_blocks = [("world", "AutoCoder")]
174
+
175
+ with patch.object(self.manager.replacers[ReplaceStrategy.STRING], 'can_handle', return_value=False):
176
+ with patch.object(self.manager.replacers[ReplaceStrategy.SIMILARITY], 'can_handle', return_value=False):
177
+ result = self.manager.replace_with_fallback(content, search_blocks)
178
+
179
+ self.assertFalse(result.success)
180
+
181
+ def test_get_available_strategies(self):
182
+ """Test getting available strategies"""
183
+ strategies = self.manager.get_available_strategies()
184
+
185
+ self.assertIsInstance(strategies, list)
186
+ self.assertIn(ReplaceStrategy.STRING, strategies)
187
+ self.assertIn(ReplaceStrategy.SIMILARITY, strategies)
188
+
189
+ def test_set_default_strategy(self):
190
+ """Test setting default strategy"""
191
+ original_default = self.manager.default_strategy
192
+
193
+ self.manager.set_default_strategy(ReplaceStrategy.SIMILARITY)
194
+ self.assertEqual(self.manager.default_strategy, ReplaceStrategy.SIMILARITY)
195
+
196
+ # Test setting unavailable strategy
197
+ with patch.object(self.manager, 'replacers', {ReplaceStrategy.STRING: MagicMock()}):
198
+ self.manager.set_default_strategy(ReplaceStrategy.PATCH)
199
+ self.assertEqual(self.manager.default_strategy, ReplaceStrategy.SIMILARITY) # Should not change
200
+
201
+ def test_configure_replacer_string(self):
202
+ """Test configuring string replacer"""
203
+ string_replacer = self.manager.get_replacer(ReplaceStrategy.STRING)
204
+ if string_replacer and isinstance(string_replacer, StringReplacer):
205
+ original_lenient = string_replacer.lenient_mode
206
+
207
+ self.manager.configure_replacer(ReplaceStrategy.STRING, lenient_mode=False)
208
+ self.assertFalse(string_replacer.lenient_mode)
209
+
210
+ # Reset
211
+ string_replacer.lenient_mode = original_lenient
212
+
213
+ def test_configure_replacer_similarity(self):
214
+ """Test configuring similarity replacer"""
215
+ similarity_replacer = self.manager.get_replacer(ReplaceStrategy.SIMILARITY)
216
+ if similarity_replacer and isinstance(similarity_replacer, SimilarityReplacer):
217
+ original_threshold = similarity_replacer.similarity_threshold
218
+
219
+ self.manager.configure_replacer(ReplaceStrategy.SIMILARITY, similarity_threshold=0.9)
220
+ self.assertEqual(similarity_replacer.similarity_threshold, 0.9)
221
+
222
+ # Reset
223
+ similarity_replacer.similarity_threshold = original_threshold
224
+
225
+ def test_configure_replacer_patch(self):
226
+ """Test configuring patch replacer"""
227
+ patch_replacer = self.manager.get_replacer(ReplaceStrategy.PATCH)
228
+ if patch_replacer and isinstance(patch_replacer, PatchReplacer):
229
+ original_use_patch_ng = patch_replacer.use_patch_ng
230
+
231
+ with patch.object(patch_replacer, '_load_patch_module'):
232
+ self.manager.configure_replacer(ReplaceStrategy.PATCH, use_patch_ng=False)
233
+ self.assertFalse(patch_replacer.use_patch_ng)
234
+
235
+ # Reset
236
+ patch_replacer.use_patch_ng = original_use_patch_ng
237
+
238
+ def test_configure_replacer_unavailable(self):
239
+ """Test configuring unavailable replacer"""
240
+ with patch.object(self.manager, 'get_replacer', return_value=None):
241
+ # Should not raise exception
242
+ self.manager.configure_replacer(ReplaceStrategy.PATCH, use_patch_ng=True)
243
+
244
+ def test_configure_replacer_exception(self):
245
+ """Test exception handling in configure_replacer"""
246
+ with patch.object(self.manager.replacers[ReplaceStrategy.STRING], 'lenient_mode',
247
+ side_effect=Exception("Config error")):
248
+ # Should not raise exception
249
+ self.manager.configure_replacer(ReplaceStrategy.STRING, lenient_mode=True)
250
+
251
+ def test_get_replacer_info_string(self):
252
+ """Test getting string replacer info"""
253
+ info = self.manager.get_replacer_info(ReplaceStrategy.STRING)
254
+
255
+ self.assertTrue(info['available'])
256
+ self.assertEqual(info['strategy'], 'string')
257
+ self.assertEqual(info['class_name'], 'StringReplacer') # Updated from RegexReplacer
258
+ self.assertIn('lenient_mode', info)
259
+
260
+ def test_get_replacer_info_similarity(self):
261
+ """Test getting similarity replacer info"""
262
+ info = self.manager.get_replacer_info(ReplaceStrategy.SIMILARITY)
263
+
264
+ self.assertTrue(info['available'])
265
+ self.assertEqual(info['strategy'], 'similarity')
266
+ self.assertEqual(info['class_name'], 'SimilarityReplacer')
267
+ self.assertIn('similarity_threshold', info)
268
+
269
+ def test_get_replacer_info_patch(self):
270
+ """Test getting patch replacer info"""
271
+ info = self.manager.get_replacer_info(ReplaceStrategy.PATCH)
272
+
273
+ if info['available']:
274
+ self.assertEqual(info['strategy'], 'patch')
275
+ self.assertEqual(info['class_name'], 'PatchReplacer')
276
+ self.assertIn('use_patch_ng', info)
277
+ self.assertIn('patch_module_available', info)
278
+
279
+ def test_get_replacer_info_unavailable(self):
280
+ """Test getting info for unavailable replacer"""
281
+ with patch.object(self.manager, 'get_replacer', return_value=None):
282
+ info = self.manager.get_replacer_info(ReplaceStrategy.PATCH)
283
+
284
+ self.assertFalse(info['available'])
285
+ self.assertEqual(info['strategy'], 'patch')
286
+
287
+ def test_get_replacer_info_exception(self):
288
+ """Test get_replacer_info with exception during info gathering"""
289
+ with patch.object(self.manager.replacers[ReplaceStrategy.STRING], 'lenient_mode',
290
+ side_effect=Exception("Mock exception")):
291
+ info = self.manager.get_replacer_info(ReplaceStrategy.STRING)
292
+
293
+ self.assertTrue(info['available'])
294
+ self.assertEqual(info['strategy'], 'string') # Updated from regex
295
+ self.assertEqual(info['class_name'], 'StringReplacer')
296
+
297
+ def test_get_status(self):
298
+ """Test get_status method"""
299
+ status = self.manager.get_status()
300
+
301
+ self.assertIn('available_strategies', status)
302
+ self.assertIn('default_strategy', status)
303
+ self.assertEqual(status['default_strategy'], 'string') # Updated from regex
304
+ self.assertIn('replacer_info', status) # Changed from 'replacers' to 'replacer_info'
305
+
306
+ def test_initialize_replacers_with_failures(self):
307
+ """Test initialization when some replacers fail to initialize"""
308
+ with patch('autocoder.common.search_replace_patch.manager.StringReplacer',
309
+ side_effect=Exception("String replacer init failed")):
310
+ with patch('autocoder.common.search_replace_patch.manager.logger') as mock_logger:
311
+ manager = SearchReplaceManager()
312
+
313
+ # Should handle initialization failures gracefully
314
+ mock_logger.error.assert_called()
315
+
316
+ # Should still have other replacers
317
+ self.assertIsInstance(manager.get_replacer(ReplaceStrategy.SIMILARITY), SimilarityReplacer)
318
+
319
+ def test_manager_with_different_defaults(self):
320
+ """Test manager with different default strategies"""
321
+ regex_manager = SearchReplaceManager(ReplaceStrategy.STRING)
322
+ similarity_manager = SearchReplaceManager(ReplaceStrategy.SIMILARITY)
323
+
324
+ self.assertEqual(regex_manager.default_strategy, ReplaceStrategy.STRING)
325
+ self.assertEqual(similarity_manager.default_strategy, ReplaceStrategy.SIMILARITY)
326
+
327
+ def test_empty_search_blocks(self):
328
+ """Test handling empty search blocks"""
329
+ content = "Hello world"
330
+ search_blocks = []
331
+
332
+ result = self.manager.replace(content, search_blocks)
333
+ self.assertFalse(result.success)
334
+
335
+ def test_integration_with_real_replacers(self):
336
+ """Test integration with real replacer instances"""
337
+ content = "Hello world"
338
+ search_blocks = [("world", "AutoCoder")]
339
+
340
+ # This should work with real replacers
341
+ result = self.manager.replace(content, search_blocks)
342
+
343
+ if result.success:
344
+ self.assertEqual(result.new_content, "Hello AutoCoder")
345
+ else:
346
+ # If it fails, it should be due to replacer logic, not manager logic
347
+ self.assertIsInstance(result.message, str)
348
+
349
+
350
+ if __name__ == '__main__':
351
+ unittest.main()
@@ -0,0 +1,316 @@
1
+ """
2
+ Test module for PatchReplacer
3
+ """
4
+
5
+ import unittest
6
+ from unittest.mock import patch, MagicMock, mock_open
7
+ import tempfile
8
+ import os
9
+
10
+ from ..patch_replacer import PatchReplacer
11
+ from ..base import ReplaceStrategy
12
+
13
+ # Type ignore for MagicMock assignments in tests
14
+ # pyright: reportAttributeAccessIssue=false
15
+
16
+
17
+ class TestPatchReplacer(unittest.TestCase):
18
+ """Test PatchReplacer functionality"""
19
+
20
+ def setUp(self):
21
+ """Set up test fixtures"""
22
+ self.replacer = PatchReplacer(use_patch_ng=True)
23
+ self.unidiff_replacer = PatchReplacer(use_patch_ng=False)
24
+
25
+ def test_initialization(self):
26
+ """Test proper initialization"""
27
+ self.assertEqual(self.replacer.strategy, ReplaceStrategy.PATCH)
28
+ self.assertTrue(self.replacer.use_patch_ng)
29
+ self.assertFalse(self.unidiff_replacer.use_patch_ng)
30
+
31
+ def test_search_blocks_to_unified_diff(self):
32
+ """Test converting search blocks to unified diff format"""
33
+ search_blocks = [
34
+ ("old_line1\nold_line2", "new_line1\nnew_line2"),
35
+ ("old_line3", "new_line3")
36
+ ]
37
+
38
+ diff = self.replacer._search_blocks_to_unified_diff(search_blocks, "test.txt")
39
+
40
+ self.assertIn("--- a/test.txt", diff)
41
+ self.assertIn("+++ b/test.txt", diff)
42
+ self.assertIn("@@", diff)
43
+ self.assertIn("-old_line1", diff)
44
+ self.assertIn("+new_line1", diff)
45
+ self.assertIn("-old_line3", diff)
46
+ self.assertIn("+new_line3", diff)
47
+
48
+ def test_replace_no_patch_module(self):
49
+ """Test replace when no patch module is available"""
50
+ replacer = PatchReplacer()
51
+ replacer._patch_module = None
52
+
53
+ content = "Hello world"
54
+ search_blocks = [("Hello", "Hi")]
55
+
56
+ result = replacer.replace(content, search_blocks)
57
+
58
+ self.assertFalse(result.success)
59
+ self.assertIn("No patch module available", result.message)
60
+
61
+ def test_replace_invalid_search_blocks(self):
62
+ """Test replace with invalid search blocks"""
63
+ content = "Hello world"
64
+
65
+ # Empty search blocks
66
+ result = self.replacer.replace(content, [])
67
+ self.assertFalse(result.success)
68
+ self.assertIn("Invalid search blocks", result.message)
69
+
70
+ # Empty search text is now valid for insertion
71
+ result = self.replacer.replace(content, [("", "replacement")])
72
+ self.assertTrue(result.success) # Should succeed as insertion
73
+
74
+ def test_can_handle(self):
75
+ """Test can_handle method"""
76
+ # Should handle valid blocks when module is available
77
+ self.replacer._patch_module = MagicMock() # type: ignore
78
+ self.assertTrue(self.replacer.can_handle("content", [("old", "new")]))
79
+
80
+ # Should not handle when no module available
81
+ self.replacer._patch_module = None
82
+ self.assertFalse(self.replacer.can_handle("content", [("old", "new")]))
83
+
84
+ # Should not handle invalid blocks
85
+ self.replacer._patch_module = MagicMock() # type: ignore
86
+ self.assertFalse(self.replacer.can_handle("content", []))
87
+
88
+ @patch('tempfile.NamedTemporaryFile')
89
+ @patch('builtins.open', new_callable=mock_open, read_data="Hello AutoCoder")
90
+ @patch('os.path.exists', return_value=True)
91
+ @patch('os.unlink')
92
+ def test_apply_patch_ng_success(self, mock_unlink, mock_exists, mock_file, mock_temp):
93
+ """Test successful patch application with patch-ng"""
94
+ # Mock temp file
95
+ mock_temp_file = MagicMock()
96
+ mock_temp_file.name = "/tmp/test.txt"
97
+ mock_temp.return_value.__enter__.return_value = mock_temp_file
98
+
99
+ # Mock patch-ng
100
+ mock_patch_module = MagicMock()
101
+ mock_patchset = MagicMock()
102
+ mock_patchset.apply.return_value = True
103
+ mock_patch_module.PatchSet.from_string.return_value = mock_patchset
104
+
105
+ self.replacer._patch_module = mock_patch_module
106
+
107
+ content = "Hello world"
108
+ diff_content = "some diff content"
109
+
110
+ result = self.replacer._apply_patch_ng(content, diff_content, "test.txt")
111
+
112
+ self.assertEqual(result, "Hello AutoCoder")
113
+ mock_patchset.apply.assert_called_once()
114
+
115
+ @patch('tempfile.NamedTemporaryFile')
116
+ def test_apply_patch_ng_failure(self, mock_temp):
117
+ """Test failed patch application with patch-ng"""
118
+ # Mock temp file
119
+ mock_temp_file = MagicMock()
120
+ mock_temp_file.name = "/tmp/test.txt"
121
+ mock_temp.return_value.__enter__.return_value = mock_temp_file
122
+
123
+ # Mock patch-ng failure
124
+ mock_patch_module = MagicMock()
125
+ mock_patchset = MagicMock()
126
+ mock_patchset.apply.return_value = False
127
+ mock_patch_module.PatchSet.from_string.return_value = mock_patchset
128
+
129
+ self.replacer._patch_module = mock_patch_module
130
+
131
+ content = "Hello world"
132
+ diff_content = "some diff content"
133
+
134
+ result = self.replacer._apply_patch_ng(content, diff_content, "test.txt")
135
+
136
+ self.assertIsNone(result)
137
+
138
+ @patch('tempfile.NamedTemporaryFile')
139
+ def test_apply_patch_ng_exception(self, mock_temp):
140
+ """Test exception handling in patch-ng application"""
141
+ # Mock temp file
142
+ mock_temp_file = MagicMock()
143
+ mock_temp_file.name = "/tmp/test.txt"
144
+ mock_temp.return_value.__enter__.return_value = mock_temp_file
145
+
146
+ # Mock patch-ng exception
147
+ mock_patch_module = MagicMock()
148
+ mock_patch_module.PatchSet.from_string.side_effect = Exception("Patch error")
149
+
150
+ self.replacer._patch_module = mock_patch_module
151
+
152
+ content = "Hello world"
153
+ diff_content = "some diff content"
154
+
155
+ result = self.replacer._apply_patch_ng(content, diff_content, "test.txt")
156
+
157
+ self.assertIsNone(result)
158
+
159
+ def test_apply_unidiff_no_patches(self):
160
+ """Test unidiff application when no patches are found"""
161
+ mock_patch_module = MagicMock()
162
+ mock_patchset = MagicMock()
163
+ mock_patchset.__bool__.return_value = False
164
+ mock_patch_module.PatchSet.return_value = mock_patchset
165
+
166
+ self.replacer._patch_module = mock_patch_module
167
+
168
+ content = "Hello world"
169
+ diff_content = "some diff content"
170
+
171
+ result = self.replacer._apply_unidiff(content, diff_content, "test.txt")
172
+
173
+ self.assertIsNone(result)
174
+
175
+ def test_apply_unidiff_success(self):
176
+ """Test successful unidiff application"""
177
+ mock_patch_module = MagicMock()
178
+ mock_patchset = MagicMock()
179
+ mock_patchset.__bool__.return_value = True
180
+ mock_patch_file = MagicMock()
181
+ mock_patchset.__getitem__.return_value = mock_patch_file
182
+ mock_patch_module.PatchSet.return_value = mock_patchset
183
+
184
+ self.replacer._patch_module = mock_patch_module
185
+
186
+ content = "Hello world"
187
+ diff_content = "some diff content"
188
+
189
+ with patch.object(self.replacer, '_apply_patch_to_lines', return_value=["Hello AutoCoder"]):
190
+ result = self.replacer._apply_unidiff(content, diff_content, "test.txt")
191
+
192
+ self.assertEqual(result, "Hello AutoCoder")
193
+
194
+ def test_apply_unidiff_exception(self):
195
+ """Test exception handling in unidiff application"""
196
+ mock_patch_module = MagicMock()
197
+ mock_patch_module.PatchSet.side_effect = Exception("Unidiff error")
198
+
199
+ self.replacer._patch_module = mock_patch_module
200
+
201
+ content = "Hello world"
202
+ diff_content = "some diff content"
203
+
204
+ result = self.replacer._apply_unidiff(content, diff_content, "test.txt")
205
+
206
+ self.assertIsNone(result)
207
+
208
+ def test_replace_with_patch_ng_success(self):
209
+ """Test successful replace using patch-ng"""
210
+ mock_patch_module = MagicMock()
211
+ self.replacer._patch_module = mock_patch_module
212
+ self.replacer.use_patch_ng = True
213
+
214
+ content = "Hello world"
215
+ search_blocks = [("Hello", "Hi")]
216
+
217
+ with patch.object(self.replacer, '_apply_patch_ng', return_value="Hi world"):
218
+ result = self.replacer.replace(content, search_blocks)
219
+
220
+ self.assertTrue(result.success)
221
+ self.assertEqual(result.new_content, "Hi world")
222
+ self.assertEqual(result.applied_count, 1)
223
+ self.assertEqual(result.total_count, 1)
224
+ self.assertEqual(result.metadata['strategy'], 'patch')
225
+ self.assertEqual(result.metadata['patch_module'], 'patch-ng')
226
+
227
+ def test_replace_with_unidiff_success(self):
228
+ """Test successful replace using unidiff"""
229
+ mock_patch_module = MagicMock()
230
+ self.replacer._patch_module = mock_patch_module
231
+ self.replacer.use_patch_ng = False
232
+
233
+ content = "Hello world"
234
+ search_blocks = [("Hello", "Hi")]
235
+
236
+ with patch.object(self.replacer, '_apply_unidiff', return_value="Hi world"):
237
+ result = self.replacer.replace(content, search_blocks)
238
+
239
+ self.assertTrue(result.success)
240
+ self.assertEqual(result.new_content, "Hi world")
241
+ self.assertEqual(result.applied_count, 1)
242
+ self.assertEqual(result.total_count, 1)
243
+ self.assertEqual(result.metadata['strategy'], 'patch')
244
+ self.assertEqual(result.metadata['patch_module'], 'unidiff')
245
+
246
+ def test_replace_patch_failure(self):
247
+ """Test replace when patch application fails"""
248
+ mock_patch_module = MagicMock()
249
+ self.replacer._patch_module = mock_patch_module
250
+
251
+ content = "Hello world"
252
+ search_blocks = [("Hello", "Hi")]
253
+
254
+ with patch.object(self.replacer, '_apply_patch_ng', return_value=None):
255
+ result = self.replacer.replace(content, search_blocks)
256
+
257
+ self.assertFalse(result.success)
258
+ self.assertIn("Failed to apply patch", result.message)
259
+ self.assertEqual(result.applied_count, 0)
260
+ self.assertEqual(result.total_count, 1)
261
+ self.assertEqual(len(result.errors), 1)
262
+
263
+ def test_replace_exception_handling(self):
264
+ """Test exception handling in replace method"""
265
+ mock_patch_module = MagicMock()
266
+ self.replacer._patch_module = mock_patch_module
267
+
268
+ content = "Hello world"
269
+ search_blocks = [("Hello", "Hi")]
270
+
271
+ with patch.object(self.replacer, '_search_blocks_to_unified_diff', side_effect=Exception("Diff error")):
272
+ result = self.replacer.replace(content, search_blocks)
273
+
274
+ self.assertFalse(result.success)
275
+ self.assertIn("Error in patch replacement", result.message)
276
+ self.assertEqual(result.applied_count, 0)
277
+ self.assertEqual(result.total_count, 1)
278
+ self.assertEqual(len(result.errors), 1)
279
+
280
+ def test_multiple_search_blocks(self):
281
+ """Test with multiple search blocks"""
282
+ mock_patch_module = MagicMock()
283
+ self.replacer._patch_module = mock_patch_module
284
+
285
+ content = "Hello world, goodbye world"
286
+ search_blocks = [
287
+ ("Hello", "Hi"),
288
+ ("goodbye", "farewell")
289
+ ]
290
+
291
+ with patch.object(self.replacer, '_apply_patch_ng', return_value="Hi world, farewell world"):
292
+ result = self.replacer.replace(content, search_blocks)
293
+
294
+ self.assertTrue(result.success)
295
+ self.assertEqual(result.new_content, "Hi world, farewell world")
296
+ self.assertEqual(result.applied_count, 2)
297
+ self.assertEqual(result.total_count, 2)
298
+
299
+ def test_diff_content_generation(self):
300
+ """Test that diff content is generated correctly"""
301
+ search_blocks = [("line1", "modified_line1")]
302
+
303
+ with patch.object(self.replacer, '_search_blocks_to_unified_diff') as mock_diff:
304
+ mock_diff.return_value = "mocked_diff"
305
+
306
+ mock_patch_module = MagicMock()
307
+ self.replacer._patch_module = mock_patch_module
308
+
309
+ with patch.object(self.replacer, '_apply_patch_ng', return_value="result"):
310
+ self.replacer.replace("content", search_blocks)
311
+
312
+ mock_diff.assert_called_once_with(search_blocks)
313
+
314
+
315
+ if __name__ == '__main__':
316
+ unittest.main()