auto-coder 1.0.0__py3-none-any.whl → 2.0.1__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.1.dist-info/LICENSE +158 -0
  2. auto_coder-2.0.1.dist-info/METADATA +558 -0
  3. auto_coder-2.0.1.dist-info/RECORD +795 -0
  4. {auto_coder-1.0.0.dist-info → auto_coder-2.0.1.dist-info}/WHEEL +1 -1
  5. {auto_coder-1.0.0.dist-info → auto_coder-2.0.1.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 +77 -73
  19. autocoder/auto_coder.py +31 -40
  20. autocoder/auto_coder_rag.py +11 -1084
  21. autocoder/auto_coder_runner.py +962 -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 +409 -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 +316 -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 +356 -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 +1094 -0
  398. autocoder/default_project/__init__.py +501 -0
  399. autocoder/dispacher/__init__.py +4 -12
  400. autocoder/dispacher/actions/action.py +400 -129
  401. autocoder/dispacher/actions/plugins/action_regex_project.py +2 -2
  402. autocoder/index/entry.py +117 -125
  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 +923 -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 +665 -0
  536. autocoder/workflow_agents/loader.py +749 -0
  537. autocoder/workflow_agents/runner.py +267 -0
  538. autocoder/workflow_agents/types.py +173 -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.1.dist-info}/top_level.txt +0 -0
  574. /autocoder/{sdk/example.py → common/agent_query_queue/__init__.py} +0 -0
@@ -1,35 +1,202 @@
1
1
  import subprocess
2
2
  import os
3
+ import time
4
+ import uuid
3
5
  from typing import Dict, Any, Optional
4
6
  from autocoder.common.run_cmd import run_cmd_subprocess
7
+ from autocoder.common.autocoderargs_parser import AutoCoderArgsParser
5
8
  from autocoder.common.v2.agent.agentic_edit_tools.base_tool_resolver import BaseToolResolver
6
- from autocoder.common.v2.agent.agentic_edit_types import ExecuteCommandTool, ToolResult # Import ToolResult from types
9
+ # Import ToolResult from types
10
+ from autocoder.common.v2.agent.agentic_edit_types import ExecuteCommandTool, ToolResult
7
11
  from autocoder.common.v2.agent.agentic_edit_tools.dangerous_command_checker import DangerousCommandChecker
8
12
  from autocoder.common import shells
9
13
  from autocoder.common.printer import Printer
10
14
  from loguru import logger
11
- import typing
15
+ import typing
12
16
  from autocoder.common.pruner.context_pruner import PruneContext
13
- from autocoder.rag.token_counter import count_tokens
17
+ from autocoder.common.tokens import count_string_tokens as count_tokens
14
18
  from autocoder.common import SourceCode
15
19
  from autocoder.common import AutoCoderArgs
16
20
  from autocoder.events.event_manager_singleton import get_event_manager
17
21
  from autocoder.run_context import get_run_context
22
+ from autocoder.common.shell_commands import (
23
+ execute_command,
24
+ execute_command_background,
25
+ execute_commands,
26
+ CommandTimeoutError,
27
+ CommandExecutionError
28
+ )
29
+ from autocoder.common.shell_commands import get_background_process_notifier
30
+ from autocoder.common.wrap_llm_hint.utils import add_hint_to_text
31
+ import shlex
32
+ import json
33
+ import yaml
34
+ from typing import List, Union
35
+ import textwrap
36
+ from pydantic import BaseModel
37
+ from datetime import datetime
38
+
18
39
  if typing.TYPE_CHECKING:
19
40
  from autocoder.common.v2.agent.agentic_edit import AgenticEdit
20
41
 
42
+
43
+ class BackgroundCommandInfo(BaseModel):
44
+ """Information about a background command execution."""
45
+ model_config = {"frozen": True, "extra": "forbid"}
46
+
47
+ pid: int
48
+ process_uniq_id: str
49
+ command: str
50
+ working_directory: str
51
+ background: bool = True
52
+ start_time: Optional[str] = None
53
+ status: str = "running"
54
+
55
+
56
+ class CommandErrorInfo(BaseModel):
57
+ """Information about a command execution error."""
58
+ model_config = {"frozen": True, "extra": "forbid"}
59
+
60
+ output: str
61
+ returncode: int
62
+
63
+
64
+ class BatchCommandSummary(BaseModel):
65
+ """Summary information for batch command execution."""
66
+ model_config = {"frozen": True, "extra": "forbid"}
67
+
68
+ total: int
69
+ successful: int
70
+ failed: int
71
+ timed_out: int
72
+ execution_mode: str
73
+
74
+
75
+ class BatchCommandContent(BaseModel):
76
+ """Content for batch command execution results."""
77
+ model_config = {"frozen": True, "extra": "forbid"}
78
+
79
+ batch_results: List[Dict[str, Any]]
80
+ summary: BatchCommandSummary
81
+
82
+
83
+ class TimeoutErrorInfo(BaseModel):
84
+ """Information about a command timeout error."""
85
+ model_config = {"frozen": True, "extra": "forbid"}
86
+
87
+ error_type: str = "timeout"
88
+ command: str
89
+ timeout_seconds: int
90
+ working_directory: str
91
+ suggested_timeout: int
92
+ original_error: str
93
+
94
+
21
95
  class ExecuteCommandToolResolver(BaseToolResolver):
22
96
  def __init__(self, agent: Optional['AgenticEdit'], tool: ExecuteCommandTool, args: AutoCoderArgs):
23
97
  super().__init__(agent, tool, args)
24
- self.tool: ExecuteCommandTool = tool # For type hinting
25
- self.context_pruner = PruneContext(
26
- max_tokens=self.args.context_prune_safe_zone_tokens,
27
- args=self.args,
28
- llm=self.agent.context_prune_llm
29
- )
98
+ self.tool: ExecuteCommandTool = tool # For type hinting
99
+
100
+ # Initialize AutoCoderArgs parser for flexible parameter parsing
101
+ self.args_parser = AutoCoderArgsParser()
102
+
103
+ # 初始化 context_pruner,使用解析后的 token 值
104
+ max_tokens = self._get_parsed_safe_zone_tokens()
105
+ llm = self.agent.context_prune_llm if self.agent else None
106
+ if llm:
107
+ self.context_pruner = PruneContext(
108
+ max_tokens=max_tokens,
109
+ args=self.args,
110
+ llm=llm
111
+ )
112
+ else:
113
+ self.context_pruner = None
30
114
  # 初始化危险命令检查器
31
115
  self.danger_checker = DangerousCommandChecker()
32
116
 
117
+ def _get_parsed_safe_zone_tokens(self) -> int:
118
+ """
119
+ 解析 context_prune_safe_zone_tokens 参数,支持多种格式
120
+
121
+ Returns:
122
+ 解析后的 token 数量
123
+ """
124
+ return self.args_parser.parse_context_prune_safe_zone_tokens(
125
+ self.args.context_prune_safe_zone_tokens,
126
+ self.args.code_model
127
+ )
128
+
129
+ def _prune_command_output_with_file_backup(self, output: str, context_name: str = "command_output") -> str:
130
+ """
131
+ 检查输出是否超过60k tokens,如果超过则裁剪并保存完整输出到文件
132
+
133
+ Args:
134
+ output: 命令输出内容
135
+ context_name: 上下文名称,用于标识输出来源
136
+
137
+ Returns:
138
+ str: 处理后的输出内容
139
+ """
140
+ if not output:
141
+ return output
142
+
143
+ try:
144
+ # 使用 tokens 模块检查 token 数量
145
+ token_count = count_tokens(output)
146
+
147
+ # 如果不超过 6k tokens,直接返回原输出
148
+ if token_count <= 6000:
149
+ return output
150
+
151
+ # 超过 6k tokens,需要裁剪并保存完整文件
152
+ logger.info(f"Output token count ({token_count}) exceeds 6k, pruning and saving to file")
153
+
154
+ # 创建保存目录
155
+ home_dir = os.path.expanduser("~")
156
+ save_dir = os.path.join(home_dir, ".auto-coder", "tool-result", "execute_command")
157
+ os.makedirs(save_dir, exist_ok=True)
158
+
159
+ # 生成文件名(时间+uuid)
160
+ timestamp = time.strftime("%Y%m%d_%H%M%S")
161
+ file_uuid = str(uuid.uuid4())[:8] # 使用前8位UUID
162
+ filename = f"{timestamp}_{file_uuid}.txt"
163
+ full_file_path = os.path.join(save_dir, filename)
164
+
165
+ # 保存完整输出到文件
166
+ with open(full_file_path, 'w', encoding='utf-8') as f:
167
+ f.write(f"# Command Output - Full Content\n")
168
+ f.write(f"# Generated at: {time.strftime('%Y-%m-%d %H:%M:%S')}\n")
169
+ f.write(f"# Context: {context_name}\n")
170
+ f.write(f"# Token count: {token_count}\n")
171
+ f.write(f"# File size: {len(output)} characters\n")
172
+ f.write(f"{'='*60}\n\n")
173
+ f.write(output)
174
+
175
+ # 获取最后6000个字符
176
+ pruned_output = output[-6000:]
177
+
178
+ # 使用 wrap_llm_hint 模块添加标准化提示信息
179
+ hint_message = f"""⚠️ OUTPUT TRUNCATED - Only showing last 6,000 characters
180
+
181
+ 📊 Original output: {token_count:,} tokens, {len(output):,} characters
182
+ 💾 Full content saved to: {full_file_path}
183
+
184
+ 💡 To read the full output or search within it, use:
185
+ read_file tool with path: {full_file_path}
186
+
187
+ You can also use the query parameter to search for specific content:
188
+ <read_file>
189
+ <path>{full_file_path}</path>
190
+ <query>your search term</query>
191
+ </read_file>"""
192
+
193
+ return add_hint_to_text(pruned_output, hint_message)
194
+
195
+ except Exception as e:
196
+ logger.error(f"Error in _prune_command_output_with_file_backup: {str(e)}")
197
+ # 如果处理失败,回退到原始的剪枝方法
198
+ return self._prune_file_content(output, context_name)
199
+
33
200
  def _prune_file_content(self, content: str, file_path: str) -> str:
34
201
  """对文件内容进行剪枝处理"""
35
202
  if not self.context_pruner:
@@ -37,7 +204,8 @@ class ExecuteCommandToolResolver(BaseToolResolver):
37
204
 
38
205
  # 计算 token 数量
39
206
  tokens = count_tokens(content)
40
- if tokens <= self.args.context_prune_safe_zone_tokens:
207
+ safe_zone_tokens = self._get_parsed_safe_zone_tokens()
208
+ if tokens <= safe_zone_tokens:
41
209
  return content
42
210
 
43
211
  # 创建 SourceCode 对象
@@ -48,62 +216,376 @@ class ExecuteCommandToolResolver(BaseToolResolver):
48
216
  )
49
217
 
50
218
  # 使用 context_pruner 进行剪枝
219
+ strategy = self.args.context_prune_strategy or "extract" # 默认策略
51
220
  pruned_sources = self.context_pruner.handle_overflow(
52
221
  file_sources=[source_code],
53
222
  conversations=self.agent.current_conversations if self.agent else [],
54
- strategy=self.args.context_prune_strategy
223
+ strategy=strategy
55
224
  )
56
225
 
57
226
  if not pruned_sources:
58
227
  return content
59
228
 
60
- return pruned_sources[0].source_code
229
+ return pruned_sources[0].source_code
230
+
231
+ def _execute_background_command(self, command: str, source_dir: str) -> ToolResult:
232
+ """执行后台命令并返回PID"""
233
+ try:
234
+ # 使用 shell_commands 模块的后台执行功能
235
+ process_info = execute_command_background(
236
+ command=command,
237
+ cwd=source_dir,
238
+ verbose=False # Use default verbose setting
239
+ )
240
+
241
+ pid = process_info["pid"]
242
+ logger.info(f"Started background command: {command} with PID: {pid}\n. Don't forget to kill the process when you don't need it.")
243
+
244
+ # Register with BackgroundProcessNotifier
245
+ try:
246
+ conversation_id = self.agent.conversation_config.conversation_id if self.agent else None
247
+ if conversation_id:
248
+ notifier = get_background_process_notifier()
249
+ notifier.register_process(
250
+ conversation_id=conversation_id,
251
+ pid=pid,
252
+ tool_name="ExecuteCommandTool",
253
+ command=command,
254
+ cwd=source_dir,
255
+ )
256
+ except Exception as e:
257
+ logger.warning(f"Failed to register background process to notifier: {e}")
258
+
259
+ # 获取 process_uniq_id
260
+ process_uniq_id = process_info.get("process_uniq_id")
261
+
262
+ # 返回成功结果,包含PID和process_uniq_id信息
263
+ background_info = BackgroundCommandInfo(
264
+ pid=pid,
265
+ process_uniq_id=process_uniq_id,
266
+ command=command,
267
+ working_directory=source_dir,
268
+ background=True,
269
+ start_time=process_info.get("start_time"),
270
+ status=process_info.get("status", "running")
271
+ )
272
+
273
+ return ToolResult(
274
+ success=True,
275
+ message=f"Background command started successfully with PID: {pid}, ID: {process_uniq_id}",
276
+ content=background_info.model_dump()
277
+ )
278
+
279
+ except Exception as e:
280
+ logger.error(f"Error starting background command '{command}': {str(e)}")
281
+ return ToolResult(
282
+ success=False,
283
+ message=f"Failed to start background command: {str(e)}"
284
+ )
285
+
286
+ def _parse_batch_commands(self, command_str: str) -> Optional[Union[List[str], Dict[str, Any]]]:
287
+ """
288
+ 解析批量命令,支持 JSON、YAML 和换行分隔格式
289
+
290
+ 返回:
291
+ - List[str]: 命令列表
292
+ - Dict: 包含 'mode' 和 'cmds' 的字典
293
+ - None: 如果不是批量命令格式
294
+ """
295
+ # 去除整体缩进,兼容 <execute_command> 标签内被统一缩进的情况
296
+ command_str = textwrap.dedent(command_str).strip()
297
+ if not command_str:
298
+ return None
299
+
300
+ # 1. 尝试 JSON 解析
301
+ try:
302
+ parsed = json.loads(command_str)
303
+ if isinstance(parsed, list) and all(isinstance(cmd, str) for cmd in parsed):
304
+ return parsed
305
+ elif isinstance(parsed, dict) and ('cmds' in parsed or 'commands' in parsed):
306
+ return parsed
307
+ except (json.JSONDecodeError, ValueError):
308
+ pass
309
+
310
+ # 2. 尝试 YAML 解析
311
+ try:
312
+ parsed = yaml.safe_load(command_str)
313
+ if isinstance(parsed, list) and all(isinstance(cmd, str) for cmd in parsed):
314
+ return parsed
315
+ elif isinstance(parsed, dict):
316
+ # 处理类似 "mode: serial\ncmds:\n - cmd1\n - cmd2" 的格式
317
+ if 'cmds' in parsed:
318
+ return parsed
319
+ # 处理简单的 key-value 对,但不是命令格式
320
+ elif not any(key in parsed for key in ['mode', 'cmds', 'commands']):
321
+ return None
322
+ except (yaml.YAMLError, ValueError):
323
+ pass
324
+
325
+ # 3. 尝试换行分隔
326
+ lines = [line.strip() for line in command_str.splitlines() if line.strip()]
327
+ if len(lines) > 1:
328
+ # 检查是否是 shell 脚本格式(第一行是 shebang 或注释)
329
+ if lines[0].startswith('#'):
330
+ # 如果第一行是 "# serial" 或 "# parallel",提取模式
331
+ if lines[0].lower() in ['# serial', '#serial']:
332
+ return {'mode': 'serial', 'cmds': lines[1:]}
333
+ elif lines[0].lower() in ['# parallel', '#parallel']:
334
+ return {'mode': 'parallel', 'cmds': lines[1:]}
335
+ # 否则当做一个命令,而不是批量命令
336
+ return None
337
+
338
+ # 不是批量命令格式
339
+ return None
340
+
341
+ def _execute_batch_commands(self, commands: Union[List[str], Dict[str, Any]], source_dir: str,
342
+ timeout: Optional[int], requires_approval: bool) -> ToolResult:
343
+ """执行批量命令"""
344
+ # 解析命令和模式
345
+ if isinstance(commands, dict):
346
+ mode = commands.get('mode', 'parallel').lower()
347
+ cmd_list = commands.get('cmds', commands.get('commands', []))
348
+ parallel = mode != 'serial'
349
+ else:
350
+ cmd_list = commands
351
+ parallel = True # 默认并行
352
+
353
+ # 确保 cmd_list 是字符串列表
354
+ if not isinstance(cmd_list, list):
355
+ return ToolResult(
356
+ success=False,
357
+ message="Invalid command list format"
358
+ )
359
+
360
+ # 类型转换和验证
361
+ validated_cmds: List[str] = []
362
+ for cmd in cmd_list:
363
+ if isinstance(cmd, str):
364
+ validated_cmds.append(cmd)
365
+ else:
366
+ return ToolResult(
367
+ success=False,
368
+ message=f"Invalid command type: expected string, got {type(cmd).__name__}"
369
+ )
370
+
371
+ if not validated_cmds:
372
+ return ToolResult(
373
+ success=False,
374
+ message="No commands found in batch command list"
375
+ )
376
+
377
+ # 危险命令检查
378
+ if self.args.enable_agentic_dangerous_command_check:
379
+ for cmd in validated_cmds:
380
+ is_safe, danger_reason = self.danger_checker.check_command_safety(
381
+ cmd, allow_whitelist_bypass=True)
382
+ if not is_safe:
383
+ recommendations = self.danger_checker.get_safety_recommendations(cmd)
384
+ error_message = f"检测到危险命令: {cmd}\n原因: {danger_reason}"
385
+ if recommendations:
386
+ error_message += f"\n安全建议:\n" + "\n".join(f"- {rec}" for rec in recommendations)
387
+ return ToolResult(success=False, message=error_message)
388
+
389
+ # 批量审批
390
+ if not self.args.enable_agentic_auto_approve and requires_approval:
391
+ approval_message = f"Allow to execute {len(validated_cmds)} commands"
392
+ if not parallel:
393
+ approval_message += " (serial execution)"
394
+ approval_message += "?\n\nCommands:\n" + "\n".join(f" {i+1}. {cmd}" for i, cmd in enumerate(validated_cmds))
395
+
396
+ try:
397
+ if get_run_context().is_web():
398
+ answer = get_event_manager(self.args.event_file).ask_user(
399
+ prompt=approval_message,
400
+ options=["yes", "no"]
401
+ )
402
+ if answer != "yes":
403
+ return ToolResult(
404
+ success=False,
405
+ message=f"Batch command execution denied by user."
406
+ )
407
+ except Exception as e:
408
+ logger.error(f"Error when asking user to approve batch commands: {str(e)}")
409
+ return ToolResult(
410
+ success=False,
411
+ message=f"An unexpected error occurred while asking for approval: {str(e)}"
412
+ )
413
+
414
+ # 执行批量命令
415
+ try:
416
+ logger.info(f"Executing {len(validated_cmds)} commands ({'parallel' if parallel else 'serial'} mode)")
417
+
418
+ # 计算超时参数
419
+ per_command_timeout = None
420
+ if timeout:
421
+ if parallel:
422
+ # 并行模式:每个命令都可以用完整的超时时间
423
+ per_command_timeout = timeout
424
+ else:
425
+ # 串行模式:平分超时时间(至少给每个命令10秒)
426
+ per_command_timeout = max(timeout / len(validated_cmds), 10.0)
427
+
428
+ # 使用 shell_commands 的批量执行功能
429
+ # 创建符合 execute_commands 类型要求的命令列表
430
+ typed_commands: List[Union[str, List[str]]] = validated_cmds # type: ignore
431
+ results = execute_commands(
432
+ commands=typed_commands,
433
+ parallel=parallel,
434
+ per_command_timeout=per_command_timeout,
435
+ timeout=timeout,
436
+ cwd=source_dir,
437
+ verbose=True
438
+ )
439
+
440
+ # 统计结果
441
+ successful = sum(1 for r in results if r['exit_code'] == 0)
442
+ failed = sum(1 for r in results if r['exit_code'] != 0 and not r['timed_out'])
443
+ timed_out = sum(1 for r in results if r['timed_out'])
444
+
445
+ # 构建汇总消息
446
+ summary_parts = []
447
+ if successful > 0:
448
+ summary_parts.append(f"{successful} succeeded")
449
+ if failed > 0:
450
+ summary_parts.append(f"{failed} failed")
451
+ if timed_out > 0:
452
+ summary_parts.append(f"{timed_out} timed out")
453
+
454
+ summary = f"Batch execution completed: {', '.join(summary_parts)}"
455
+
456
+ # 对每个命令的输出进行裁剪
457
+ for result in results:
458
+ if 'output' in result and result['output']:
459
+ result['output'] = self._prune_command_output_with_file_backup(
460
+ result['output'],
461
+ f"command_{result['index']}_output"
462
+ )
463
+
464
+ batch_summary = BatchCommandSummary(
465
+ total=len(results),
466
+ successful=successful,
467
+ failed=failed,
468
+ timed_out=timed_out,
469
+ execution_mode='parallel' if parallel else 'serial'
470
+ )
471
+
472
+ batch_content = BatchCommandContent(
473
+ batch_results=results,
474
+ summary=batch_summary
475
+ )
476
+
477
+ return ToolResult(
478
+ success=all(r['exit_code'] == 0 for r in results),
479
+ message=summary,
480
+ content=batch_content.model_dump()
481
+ )
482
+
483
+ except Exception as e:
484
+ logger.error(f"Error executing batch commands: {str(e)}")
485
+ return ToolResult(
486
+ success=False,
487
+ message=f"An unexpected error occurred while executing batch commands: {str(e)}"
488
+ )
61
489
 
62
- def resolve(self) -> ToolResult:
490
+ def resolve(self) -> ToolResult:
63
491
  command = self.tool.command
64
492
  requires_approval = self.tool.requires_approval
493
+ background = self.tool.background # 获取后台运行选项
65
494
  source_dir = self.args.source_dir or "."
66
495
 
496
+ # 尝试解析批量命令
497
+ batch_commands = self._parse_batch_commands(command)
498
+ if batch_commands is not None:
499
+ # 检查是否是批量命令(多于1个命令)
500
+ if isinstance(batch_commands, list) and len(batch_commands) > 1:
501
+ # 是批量命令列表
502
+ return self._execute_batch_commands(batch_commands, source_dir, self.tool.timeout, requires_approval)
503
+ elif isinstance(batch_commands, dict) and (batch_commands.get('cmds') or batch_commands.get('commands')):
504
+ # 是包含命令列表的字典格式
505
+ return self._execute_batch_commands(batch_commands, source_dir, self.tool.timeout, requires_approval)
506
+ # 如果只有一个命令,继续按单个命令处理
507
+ elif isinstance(batch_commands, list) and len(batch_commands) == 1:
508
+ command = batch_commands[0]
509
+ elif isinstance(batch_commands, dict):
510
+ # 检查是否只有一个命令
511
+ cmd_list = batch_commands.get('cmds', batch_commands.get('commands', []))
512
+ if len(cmd_list) == 1:
513
+ command = cmd_list[0]
514
+
67
515
  if self.args.enable_agentic_dangerous_command_check:
68
516
  # 使用新的危险命令检查器进行安全检查
69
- is_safe, danger_reason = self.danger_checker.check_command_safety(command, allow_whitelist_bypass=True)
70
-
517
+ is_safe, danger_reason = self.danger_checker.check_command_safety(
518
+ command, allow_whitelist_bypass=True)
519
+
71
520
  if not is_safe:
72
521
  # 获取安全建议
73
- recommendations = self.danger_checker.get_safety_recommendations(command)
74
-
522
+ recommendations = self.danger_checker.get_safety_recommendations(
523
+ command)
524
+
75
525
  error_message = f"检测到危险命令: {danger_reason}"
76
526
  if recommendations:
77
- error_message += f"\n安全建议:\n" + "\n".join(f"- {rec}" for rec in recommendations)
78
-
527
+ error_message += f"\n安全建议:\n" + \
528
+ "\n".join(f"- {rec}" for rec in recommendations)
529
+
79
530
  logger.warning(f"阻止执行危险命令: {command}, 原因: {danger_reason}")
80
531
  return ToolResult(success=False, message=error_message)
81
532
 
82
533
  # Approval mechanism (simplified)
83
534
  if not self.args.enable_agentic_auto_approve and requires_approval:
84
- logger.info(f"Executing command: {command} in {os.path.abspath(source_dir)}")
85
- try:
535
+ logger.info(
536
+ f"Executing command: {command} in {os.path.abspath(source_dir)}")
537
+ try:
86
538
  # 使用封装的run_cmd方法执行命令
87
539
  if get_run_context().is_web():
88
540
  answer = get_event_manager(
89
- self.args.event_file).ask_user(prompt=f"Allow to execute the `{command}`?",options=["yes","no"])
541
+ self.args.event_file).ask_user(prompt=f"Allow to execute the `{command}`?", options=["yes", "no"])
90
542
  if answer == "yes":
91
543
  pass
92
544
  else:
93
545
  return ToolResult(success=False, message=f"Command '{command}' execution denied by user.")
94
546
  except Exception as e:
95
- logger.error(f"Error when ask the user to approve the command '{command}': {str(e)}")
547
+ logger.error(
548
+ f"Error when ask the user to approve the command '{command}': {str(e)}")
96
549
  return ToolResult(success=False, message=f"An unexpected error occurred while asking the user to approve the command: {str(e)}")
97
-
98
- try:
99
- exit_code, output = run_cmd_subprocess(command, verbose=True, cwd=source_dir)
550
+
551
+ # 如果是后台运行,使用专门的后台执行方法
552
+ if background:
553
+ return self._execute_background_command(command, source_dir)
554
+
555
+ # 如果不是后台运行,继续使用原来的前台执行逻辑
556
+ try:
557
+ # 根据配置选择使用新的 shell_commands 模块还是旧的 run_cmd 模块
558
+ use_shell_commands = self.args.use_shell_commands
559
+
560
+ # 获取超时参数
561
+ timeout = self.tool.timeout # 使用工具中的超时参数
562
+
563
+ if use_shell_commands:
564
+ # 使用新的 shell_commands 模块
565
+ logger.debug(
566
+ f"Using shell_commands module for command execution (timeout: {timeout}s)")
567
+ try:
568
+ exit_code, output = execute_command(
569
+ command, timeout=timeout, verbose=True, cwd=source_dir)
570
+ except CommandTimeoutError as e:
571
+ logger.error(f"Command timed out: {e}")
572
+ return self._build_timeout_error_result(command, timeout, source_dir, e)
573
+ except CommandExecutionError as e:
574
+ logger.error(f"Command execution failed: {e}")
575
+ return ToolResult(success=False, message=f"Command execution failed: {str(e)}")
576
+ else:
577
+ # 使用旧的 run_cmd 模块(不支持超时)
578
+ logger.debug("Using run_cmd module for command execution (note: timeout not supported)")
579
+ exit_code, output = run_cmd_subprocess(
580
+ command, verbose=True, cwd=source_dir)
100
581
 
101
582
  logger.info(f"Command executed: {command}")
102
583
  logger.info(f"Return Code: {exit_code}")
103
584
  if output:
104
- logger.info(f"Original Output (length: {len(output)} chars)") # Avoid logging potentially huge output directly
585
+ # Avoid logging potentially huge output directly
586
+ logger.info(f"Original Output (length: {len(output)} chars)")
105
587
 
106
- final_output = self._prune_file_content(output, "command_output")
588
+ final_output = self._prune_command_output_with_file_backup(output, "command_output")
107
589
 
108
590
  if exit_code == 0:
109
591
  return ToolResult(success=True, message="Command executed successfully.", content=final_output)
@@ -111,7 +593,13 @@ class ExecuteCommandToolResolver(BaseToolResolver):
111
593
  # For the human-readable error message, we might prefer the original full output.
112
594
  # For the agent-consumable content, we provide the (potentially pruned) final_output.
113
595
  error_message_for_human = f"Command failed with return code {exit_code}.\nOutput:\n{output}"
114
- return ToolResult(success=False, message=error_message_for_human, content={"output": final_output, "returncode": exit_code})
596
+
597
+ error_info = CommandErrorInfo(
598
+ output=final_output,
599
+ returncode=exit_code
600
+ )
601
+
602
+ return ToolResult(success=False, message=error_message_for_human, content=error_info.model_dump())
115
603
 
116
604
  except FileNotFoundError:
117
605
  return ToolResult(success=False, message=f"Error: The command '{command.split()[0]}' was not found. Please ensure it is installed and in the system's PATH.")
@@ -120,3 +608,50 @@ class ExecuteCommandToolResolver(BaseToolResolver):
120
608
  except Exception as e:
121
609
  logger.error(f"Error executing command '{command}': {str(e)}")
122
610
  return ToolResult(success=False, message=f"An unexpected error occurred while executing the command: {str(e)}")
611
+
612
+ def _build_timeout_error_result(self, command: str, timeout: Optional[int], source_dir: str, error: Exception) -> ToolResult:
613
+ """构建超时错误结果"""
614
+ # 处理超时值,确保不为 None
615
+ actual_timeout = timeout if timeout is not None else 60
616
+ suggested_timeout = actual_timeout * 2
617
+
618
+ # 构建基本错误信息
619
+ basic_error = f"""COMMAND TIMEOUT ERROR
620
+
621
+ Command: {command}
622
+ Timeout: {actual_timeout} seconds
623
+ Directory: {source_dir}
624
+
625
+ The command failed to complete within the specified timeout period."""
626
+
627
+ # 构建详细的建议信息作为 hint
628
+ suggestions_hint = f"""This usually indicates that:
629
+ 1. The command is taking longer than expected to execute
630
+ 2. The command may be waiting for user input or hanging
631
+ 3. The command is processing large amounts of data
632
+
633
+ Suggestions:
634
+ • Increase the timeout value using: <timeout>{suggested_timeout}</timeout>
635
+ • Check if the command requires user interaction
636
+ • Consider breaking down complex commands into smaller steps
637
+ • Verify the command syntax and parameters are correct
638
+
639
+ Error details: {str(error)}"""
640
+
641
+ # 使用 wrap_llm_hint 模块添加标准化提示信息
642
+ timeout_message = add_hint_to_text(basic_error, suggestions_hint)
643
+
644
+ timeout_info = TimeoutErrorInfo(
645
+ error_type="timeout",
646
+ command=command,
647
+ timeout_seconds=actual_timeout,
648
+ working_directory=source_dir,
649
+ suggested_timeout=suggested_timeout,
650
+ original_error=str(error)
651
+ )
652
+
653
+ return ToolResult(
654
+ success=False,
655
+ message=timeout_message,
656
+ content=timeout_info.model_dump()
657
+ )