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,305 @@
1
+ """
2
+ Tests for error recovery functionality.
3
+
4
+ This module tests the error recovery mechanisms used in shell command execution.
5
+ """
6
+
7
+ import pytest
8
+ import time
9
+ from unittest.mock import Mock, patch
10
+
11
+ from autocoder.common.shell_commands.error_recovery import (
12
+ ErrorRecoveryManager,
13
+ RetryConfig,
14
+ create_default_error_recovery_manager,
15
+ retry_with_backoff
16
+ )
17
+ from autocoder.common.shell_commands.exceptions import (
18
+ CommandExecutionError,
19
+ CommandTimeoutError,
20
+ ErrorRecoveryFailedError
21
+ )
22
+
23
+
24
+ class TestRetryConfig:
25
+ """Test cases for RetryConfig class."""
26
+
27
+ def test_initialization_defaults(self):
28
+ """Test RetryConfig initialization with default values."""
29
+ config = RetryConfig()
30
+ assert config.max_attempts == 3
31
+ assert config.base_delay == 1.0
32
+ assert config.max_delay == 60.0
33
+ assert config.backoff_factor == 2.0
34
+ assert config.retry_on_timeout is True
35
+ assert config.retry_on_cleanup_error is True
36
+
37
+ def test_initialization_custom(self):
38
+ """Test RetryConfig initialization with custom values."""
39
+ config = RetryConfig(
40
+ max_attempts=5,
41
+ base_delay=2.0,
42
+ max_delay=120.0,
43
+ backoff_factor=3.0,
44
+ retry_on_timeout=False,
45
+ retry_on_cleanup_error=False
46
+ )
47
+ assert config.max_attempts == 5
48
+ assert config.base_delay == 2.0
49
+ assert config.max_delay == 120.0
50
+ assert config.backoff_factor == 3.0
51
+ assert config.retry_on_timeout is False
52
+ assert config.retry_on_cleanup_error is False
53
+
54
+ def test_get_delay_exponential_backoff(self):
55
+ """Test exponential backoff delay calculation."""
56
+ config = RetryConfig(base_delay=1.0, backoff_factor=2.0, max_delay=10.0, jitter=False)
57
+
58
+ assert config.get_delay(0) == 1.0 # base_delay * 2^0
59
+ assert config.get_delay(1) == 2.0 # base_delay * 2^1
60
+ assert config.get_delay(2) == 4.0 # base_delay * 2^2
61
+
62
+ def test_get_delay_max_limit(self):
63
+ """Test that delay calculation respects maximum limit."""
64
+ config = RetryConfig(base_delay=1.0, backoff_factor=2.0, max_delay=5.0, jitter=False)
65
+
66
+ # Even with exponential backoff, delay should not exceed max_delay
67
+ delay_high = config.get_delay(10) # Very high attempt number
68
+ assert delay_high <= 5.0
69
+
70
+ def test_should_retry_timeout_error(self):
71
+ """Test retry decision for timeout errors."""
72
+ config = RetryConfig(retry_on_timeout=True)
73
+ timeout_error = CommandTimeoutError("test", 5.0, 123)
74
+ assert config.should_retry(timeout_error, 0)
75
+ assert config.should_retry(timeout_error, 1)
76
+ assert config.should_retry(timeout_error, 2)
77
+ assert not config.should_retry(timeout_error, 3) # Max attempts reached
78
+
79
+ def test_should_retry_timeout_disabled(self):
80
+ """Test retry decision when timeout retry is disabled."""
81
+ config = RetryConfig(retry_on_timeout=False)
82
+ timeout_error = CommandTimeoutError("test", 5.0, 123)
83
+ assert not config.should_retry(timeout_error, 0)
84
+
85
+ def test_should_retry_generic_error(self):
86
+ """Test retry decision for generic errors."""
87
+ config = RetryConfig()
88
+ generic_error = Exception("Generic error")
89
+ assert not config.should_retry(generic_error, 0)
90
+
91
+
92
+ class TestErrorRecoveryManager:
93
+ """Test cases for ErrorRecoveryManager class."""
94
+
95
+ def test_initialization_defaults(self):
96
+ """Test manager initialization with default values."""
97
+ manager = ErrorRecoveryManager()
98
+ assert manager.max_recovery_attempts == 3
99
+ assert len(manager.recovery_strategies) > 0
100
+
101
+ def test_initialization_custom(self):
102
+ """Test manager initialization with custom values."""
103
+ manager = ErrorRecoveryManager(max_recovery_attempts=5)
104
+ assert manager.max_recovery_attempts == 5
105
+
106
+ def test_register_recovery_strategy(self):
107
+ """Test registering custom recovery strategies."""
108
+ manager = ErrorRecoveryManager()
109
+
110
+ def custom_strategy(error, context, retry_count):
111
+ return True
112
+
113
+ manager.register_recovery_strategy(ValueError, custom_strategy)
114
+ assert ValueError in manager.recovery_strategies
115
+
116
+ def test_handle_error_success(self):
117
+ """Test successful error recovery."""
118
+ manager = ErrorRecoveryManager()
119
+
120
+ # Mock a successful recovery
121
+ def mock_strategy(error, context, retry_count):
122
+ return True
123
+
124
+ manager.register_recovery_strategy(ValueError, mock_strategy)
125
+
126
+ error = ValueError("Test error")
127
+ result = manager.handle_error(error)
128
+ assert result is True
129
+
130
+ def test_handle_error_failure(self):
131
+ """Test failed error recovery."""
132
+ manager = ErrorRecoveryManager(max_recovery_attempts=1)
133
+
134
+ # Mock a failed recovery
135
+ def mock_strategy(error, context, retry_count):
136
+ return False
137
+
138
+ manager.register_recovery_strategy(ValueError, mock_strategy)
139
+
140
+ error = ValueError("Test error")
141
+ with pytest.raises(ErrorRecoveryFailedError):
142
+ manager.handle_error(error)
143
+
144
+ def test_handle_error_no_strategy(self):
145
+ """Test error handling when no strategy is available."""
146
+ manager = ErrorRecoveryManager()
147
+
148
+ # Use an error type that doesn't have a strategy
149
+ error = KeyError("Test error")
150
+ result = manager.handle_error(error)
151
+ assert result is False
152
+
153
+
154
+ class TestRetryWithBackoff:
155
+ """Test cases for retry_with_backoff function."""
156
+
157
+ def test_retry_success_on_first_try(self):
158
+ """Test successful execution on first try."""
159
+ call_count = 0
160
+
161
+ def successful_func():
162
+ nonlocal call_count
163
+ call_count += 1
164
+ return "success"
165
+
166
+ config = RetryConfig()
167
+ result = retry_with_backoff(successful_func, config)
168
+
169
+ assert result == "success"
170
+ assert call_count == 1
171
+
172
+ def test_retry_success_after_failures(self):
173
+ """Test successful execution after initial failures."""
174
+ call_count = 0
175
+
176
+ def flaky_func():
177
+ nonlocal call_count
178
+ call_count += 1
179
+ if call_count < 3:
180
+ raise CommandTimeoutError("test", 5.0, 123)
181
+ return "success"
182
+
183
+ config = RetryConfig(max_attempts=5, retry_on_timeout=True)
184
+ result = retry_with_backoff(flaky_func, config)
185
+
186
+ assert result == "success"
187
+ assert call_count == 3
188
+
189
+ def test_retry_max_attempts_exceeded(self):
190
+ """Test behavior when max attempts is exceeded."""
191
+ call_count = 0
192
+
193
+ def always_fail_func():
194
+ nonlocal call_count
195
+ call_count += 1
196
+ raise CommandTimeoutError("test", 5.0, 123)
197
+
198
+ config = RetryConfig(max_attempts=2, retry_on_timeout=True)
199
+ with pytest.raises(CommandTimeoutError):
200
+ retry_with_backoff(always_fail_func, config)
201
+
202
+ assert call_count == 2
203
+
204
+ def test_retry_non_retryable_error(self):
205
+ """Test behavior with non-retryable errors."""
206
+ call_count = 0
207
+
208
+ def non_retryable_func():
209
+ nonlocal call_count
210
+ call_count += 1
211
+ raise ValueError("Not retryable")
212
+
213
+ config = RetryConfig()
214
+ with pytest.raises(ValueError):
215
+ retry_with_backoff(non_retryable_func, config)
216
+
217
+ assert call_count == 1
218
+
219
+ @patch('time.sleep')
220
+ def test_retry_delay_timing(self, mock_sleep):
221
+ """Test that delays are applied correctly."""
222
+ call_count = 0
223
+
224
+ def failing_func():
225
+ nonlocal call_count
226
+ call_count += 1
227
+ if call_count < 3:
228
+ raise CommandTimeoutError("test", 5.0, 123)
229
+ return "success"
230
+
231
+ config = RetryConfig(base_delay=1.0, max_attempts=3, retry_on_timeout=True, jitter=False)
232
+ result = retry_with_backoff(failing_func, config)
233
+
234
+ assert result == "success"
235
+ assert mock_sleep.call_count == 2 # Two retries, two delays
236
+
237
+ # Check that delays follow expected pattern
238
+ expected_delays = [1.0, 2.0] # Exponential backoff
239
+ actual_delays = [call.args[0] for call in mock_sleep.call_args_list]
240
+ assert actual_delays == expected_delays
241
+
242
+
243
+ class TestDefaultErrorRecoveryManager:
244
+ """Test cases for default error recovery manager."""
245
+
246
+ def test_create_default_manager(self):
247
+ """Test creating default error recovery manager."""
248
+ manager = create_default_error_recovery_manager()
249
+ assert isinstance(manager, ErrorRecoveryManager)
250
+ assert manager.max_recovery_attempts == 3
251
+ assert len(manager.recovery_strategies) > 0
252
+
253
+ def test_default_timeout_error_handling(self):
254
+ """Test default handling of timeout errors."""
255
+ manager = create_default_error_recovery_manager()
256
+
257
+ timeout_error = CommandTimeoutError("test", 5.0, 123)
258
+ context = {}
259
+
260
+ # Should attempt recovery
261
+ result = manager.handle_error(timeout_error, context)
262
+ assert result is True # Should succeed on first try with increased timeout
263
+ assert 'timeout' in context # Context should be updated with new timeout
264
+
265
+
266
+ class TestErrorRecoveryEdgeCases:
267
+ """Test cases for edge cases and error conditions."""
268
+
269
+ def test_zero_max_attempts(self):
270
+ """Test behavior with zero max attempts."""
271
+ config = RetryConfig(max_attempts=0)
272
+
273
+ def failing_func():
274
+ raise CommandTimeoutError("test", 5.0, 123)
275
+
276
+ with pytest.raises(CommandTimeoutError):
277
+ retry_with_backoff(failing_func, config)
278
+
279
+ def test_negative_delay_values(self):
280
+ """Test behavior with negative delay values."""
281
+ config = RetryConfig(base_delay=-1.0)
282
+
283
+ # Should handle negative delays gracefully
284
+ delay = config.get_delay(1)
285
+ assert delay >= 0 # Should not return negative delays
286
+
287
+ def test_function_with_side_effects(self):
288
+ """Test retry behavior with functions that have side effects."""
289
+ side_effects = []
290
+
291
+ def side_effect_func():
292
+ side_effects.append("called")
293
+ if len(side_effects) < 2:
294
+ raise CommandTimeoutError("test", 5.0, 123)
295
+ return "success"
296
+
297
+ config = RetryConfig(max_attempts=3, retry_on_timeout=True)
298
+ result = retry_with_backoff(side_effect_func, config)
299
+
300
+ assert result == "success"
301
+ assert len(side_effects) == 2
302
+
303
+
304
+ if __name__ == "__main__":
305
+ pytest.main([__file__, "-v"])
@@ -0,0 +1,299 @@
1
+ """
2
+ Tests for shell command exceptions.
3
+
4
+ This module tests the custom exception classes used in the shell command system.
5
+ """
6
+
7
+ import pytest
8
+
9
+ from autocoder.common.shell_commands.exceptions import (
10
+ CommandExecutionError,
11
+ CommandTimeoutError,
12
+ ProcessCleanupError,
13
+ ProcessNotFoundError,
14
+ TimeoutConfigError,
15
+ ErrorRecoveryFailedError
16
+ )
17
+
18
+
19
+ class TestCommandExecutionError:
20
+ """Test cases for CommandExecutionError."""
21
+
22
+ def test_basic_creation(self):
23
+ """Test basic exception creation."""
24
+ error = CommandExecutionError("Test error message")
25
+ assert str(error) == "Test error message"
26
+ assert isinstance(error, Exception)
27
+
28
+ def test_inheritance(self):
29
+ """Test that CommandExecutionError inherits from Exception."""
30
+ error = CommandExecutionError("Test")
31
+ assert isinstance(error, Exception)
32
+
33
+ def test_empty_message(self):
34
+ """Test exception with empty message."""
35
+ error = CommandExecutionError("")
36
+ assert str(error) == ""
37
+ assert isinstance(error, Exception)
38
+
39
+
40
+ class TestCommandTimeoutError:
41
+ """Test cases for CommandTimeoutError."""
42
+
43
+ def test_basic_creation(self):
44
+ """Test basic timeout error creation."""
45
+ error = CommandTimeoutError("sleep 10", 5.0, 12345)
46
+ assert "sleep 10" in str(error)
47
+ assert "5.0" in str(error)
48
+ assert "12345" in str(error)
49
+
50
+ def test_attributes(self):
51
+ """Test timeout error attributes."""
52
+ error = CommandTimeoutError("test command", 3.0, 999)
53
+ assert error.command == "test command"
54
+ assert error.timeout == 3.0
55
+ assert error.pid == 999
56
+
57
+ def test_without_pid(self):
58
+ """Test timeout error without PID."""
59
+ error = CommandTimeoutError("echo hello", 2.5)
60
+ assert error.command == "echo hello"
61
+ assert error.timeout == 2.5
62
+ assert error.pid is None
63
+ assert "echo hello" in str(error)
64
+ assert "2.5" in str(error)
65
+
66
+ def test_string_representation(self):
67
+ """Test string representation of timeout error."""
68
+ error = CommandTimeoutError("echo hello", 2.5, 1234)
69
+ error_str = str(error)
70
+ assert "echo hello" in error_str
71
+ assert "2.5" in error_str
72
+ assert "1234" in error_str
73
+ assert "timed out" in error_str.lower()
74
+
75
+ def test_repr(self):
76
+ """Test __repr__ method."""
77
+ error = CommandTimeoutError("test", 1.0, 123)
78
+ repr_str = repr(error)
79
+ assert "CommandTimeoutError" in repr_str
80
+ assert "test" in repr_str
81
+ assert "1.0" in repr_str
82
+ assert "123" in repr_str
83
+
84
+ def test_inheritance(self):
85
+ """Test inheritance from CommandExecutionError."""
86
+ error = CommandTimeoutError("test", 1.0, 123)
87
+ assert isinstance(error, CommandExecutionError)
88
+ assert isinstance(error, Exception)
89
+
90
+
91
+ class TestProcessCleanupError:
92
+ """Test cases for ProcessCleanupError."""
93
+
94
+ def test_basic_creation(self):
95
+ """Test basic process cleanup error creation."""
96
+ error = ProcessCleanupError(1234, "Failed to cleanup process")
97
+ assert error.pid == 1234
98
+ assert error.original_message == "Failed to cleanup process"
99
+ assert "1234" in str(error)
100
+ assert "Failed to cleanup process" in str(error)
101
+
102
+ def test_string_representation(self):
103
+ """Test string representation."""
104
+ error = ProcessCleanupError(5678, "Process is still running")
105
+ error_str = str(error)
106
+ assert "5678" in error_str
107
+ assert "Process is still running" in error_str
108
+ assert "Failed to cleanup process" in error_str
109
+
110
+ def test_repr(self):
111
+ """Test __repr__ method."""
112
+ error = ProcessCleanupError(999, "Test message")
113
+ repr_str = repr(error)
114
+ assert "ProcessCleanupError" in repr_str
115
+ assert "999" in repr_str
116
+ assert "Test message" in repr_str
117
+
118
+ def test_inheritance(self):
119
+ """Test inheritance from CommandExecutionError."""
120
+ error = ProcessCleanupError(123, "test")
121
+ assert isinstance(error, CommandExecutionError)
122
+ assert isinstance(error, Exception)
123
+
124
+
125
+ class TestProcessNotFoundError:
126
+ """Test cases for ProcessNotFoundError."""
127
+
128
+ def test_basic_creation(self):
129
+ """Test basic process not found error creation."""
130
+ error = ProcessNotFoundError(1234)
131
+ assert error.pid == 1234
132
+ assert "1234" in str(error)
133
+ assert "not found" in str(error).lower()
134
+
135
+ def test_repr(self):
136
+ """Test __repr__ method."""
137
+ error = ProcessNotFoundError(999)
138
+ repr_str = repr(error)
139
+ assert "ProcessNotFoundError" in repr_str
140
+ assert "999" in repr_str
141
+
142
+ def test_inheritance(self):
143
+ """Test inheritance from CommandExecutionError."""
144
+ error = ProcessNotFoundError(123)
145
+ assert isinstance(error, CommandExecutionError)
146
+ assert isinstance(error, Exception)
147
+
148
+
149
+ class TestTimeoutConfigError:
150
+ """Test cases for TimeoutConfigError."""
151
+
152
+ def test_basic_creation(self):
153
+ """Test basic timeout config error creation."""
154
+ error = TimeoutConfigError("default_timeout", -1, "Timeout must be positive")
155
+ assert error.config_field == "default_timeout"
156
+ assert error.value == -1
157
+ assert error.reason == "Timeout must be positive"
158
+
159
+ def test_string_representation(self):
160
+ """Test string representation."""
161
+ error = TimeoutConfigError("max_timeout", "invalid", "Must be a number")
162
+ error_str = str(error)
163
+ assert "max_timeout" in error_str
164
+ assert "invalid" in error_str
165
+ assert "Must be a number" in error_str
166
+
167
+ def test_repr(self):
168
+ """Test __repr__ method."""
169
+ error = TimeoutConfigError("test_field", 123, "test reason")
170
+ repr_str = repr(error)
171
+ assert "TimeoutConfigError" in repr_str
172
+ assert "test_field" in repr_str
173
+ assert "123" in repr_str
174
+ assert "test reason" in repr_str
175
+
176
+ def test_inheritance(self):
177
+ """Test inheritance from CommandExecutionError."""
178
+ error = TimeoutConfigError("test", 1, "test")
179
+ assert isinstance(error, CommandExecutionError)
180
+ assert isinstance(error, Exception)
181
+
182
+
183
+ class TestErrorRecoveryFailedError:
184
+ """Test cases for ErrorRecoveryFailedError."""
185
+
186
+ def test_basic_creation(self):
187
+ """Test basic error recovery failed error creation."""
188
+ original_error = ValueError("Original error")
189
+ error = ErrorRecoveryFailedError(original_error, 3)
190
+ assert error.original_error is original_error
191
+ assert error.recovery_attempts == 3
192
+ assert "3 attempts" in str(error)
193
+ assert "Original error" in str(error)
194
+
195
+ def test_with_different_original_error(self):
196
+ """Test with different types of original errors."""
197
+ original_error = CommandTimeoutError("test", 1.0, 123)
198
+ error = ErrorRecoveryFailedError(original_error, 5)
199
+ assert error.original_error is original_error
200
+ assert error.recovery_attempts == 5
201
+ assert "5 attempts" in str(error)
202
+
203
+ def test_repr(self):
204
+ """Test __repr__ method."""
205
+ original_error = RuntimeError("Test error")
206
+ error = ErrorRecoveryFailedError(original_error, 2)
207
+ repr_str = repr(error)
208
+ assert "ErrorRecoveryFailedError" in repr_str
209
+ assert "2" in repr_str
210
+
211
+ def test_inheritance(self):
212
+ """Test inheritance from CommandExecutionError."""
213
+ original_error = Exception("test")
214
+ error = ErrorRecoveryFailedError(original_error, 1)
215
+ assert isinstance(error, CommandExecutionError)
216
+ assert isinstance(error, Exception)
217
+
218
+
219
+ class TestExceptionInteraction:
220
+ """Test cases for exception interaction and edge cases."""
221
+
222
+ def test_exception_chaining(self):
223
+ """Test exception chaining scenarios."""
224
+ try:
225
+ raise CommandExecutionError("Original error")
226
+ except CommandExecutionError as e:
227
+ timeout_error = CommandTimeoutError("test", 1.0, 123)
228
+ timeout_error.__cause__ = e
229
+ assert timeout_error.__cause__ is e
230
+
231
+ def test_multiple_exception_types(self):
232
+ """Test handling multiple exception types."""
233
+ exec_error = CommandExecutionError("Execution failed")
234
+ timeout_error = CommandTimeoutError("timeout test", 5.0, 456)
235
+ cleanup_error = ProcessCleanupError(789, "Cleanup failed")
236
+
237
+ errors = [exec_error, timeout_error, cleanup_error]
238
+
239
+ for error in errors:
240
+ assert isinstance(error, Exception)
241
+
242
+ # Test that all errors inherit from CommandExecutionError
243
+ for error in errors:
244
+ assert isinstance(error, CommandExecutionError)
245
+
246
+ def test_exception_with_none_values(self):
247
+ """Test exceptions with None values."""
248
+ # Test CommandTimeoutError with None PID
249
+ error = CommandTimeoutError("test", 5.0, None)
250
+ assert error.command == "test"
251
+ assert error.timeout == 5.0
252
+ assert error.pid is None
253
+
254
+ # Should still be convertible to string
255
+ str_repr = str(error)
256
+ assert isinstance(str_repr, str)
257
+ assert "test" in str_repr
258
+
259
+ def test_exception_pickling(self):
260
+ """Test that exceptions can be pickled (for multiprocessing)."""
261
+ import pickle
262
+
263
+ # Test basic exception pickling
264
+ error1 = CommandExecutionError("Test execution error")
265
+ pickled1 = pickle.dumps(error1)
266
+ unpickled1 = pickle.loads(pickled1)
267
+ assert str(unpickled1) == str(error1)
268
+
269
+ # Test that custom exceptions at least create proper string representations
270
+ timeout_error = CommandTimeoutError("test", 5.0, 123)
271
+ cleanup_error = ProcessCleanupError(456, "Test cleanup error")
272
+
273
+ # These should at least have proper string representations
274
+ assert str(timeout_error)
275
+ assert str(cleanup_error)
276
+ assert repr(timeout_error)
277
+ assert repr(cleanup_error)
278
+
279
+ # Note: Custom exceptions with complex __init__ may have pickling issues
280
+ # This is acceptable as they're primarily used for immediate error handling
281
+
282
+ def test_all_exceptions_are_command_execution_errors(self):
283
+ """Test that all custom exceptions inherit from CommandExecutionError."""
284
+ exceptions = [
285
+ CommandExecutionError("test"),
286
+ CommandTimeoutError("test", 1.0, 123),
287
+ ProcessCleanupError(123, "test"),
288
+ ProcessNotFoundError(456),
289
+ TimeoutConfigError("test", "value", "reason"),
290
+ ErrorRecoveryFailedError(Exception("test"), 1)
291
+ ]
292
+
293
+ for exc in exceptions:
294
+ assert isinstance(exc, CommandExecutionError)
295
+ assert isinstance(exc, Exception)
296
+
297
+
298
+ if __name__ == "__main__":
299
+ pytest.main([__file__, "-v"])