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
@@ -14,7 +14,6 @@ import byzerllm
14
14
  from pydantic import BaseModel
15
15
 
16
16
  from autocoder.common import AutoCoderArgs, git_utils, SourceCodeList, SourceCode
17
- from autocoder.common.global_cancel import global_cancel
18
17
  from autocoder.rag.variable_holder import VariableHolder
19
18
  from autocoder.utils import llms as llms_utils
20
19
  from autocoder.common.global_cancel import global_cancel
@@ -22,13 +21,9 @@ from autocoder.common import detect_env
22
21
  from autocoder.common import shells
23
22
  from autocoder.common.printer import Printer
24
23
  from autocoder.utils.auto_project_type import ProjectTypeAnalyzer
25
- from autocoder.common.mcp_server import get_mcp_server, McpServerInfoRequest
24
+ from autocoder.common.mcp_tools.server import get_mcp_server, McpServerInfoRequest
26
25
  from autocoder.common.file_monitor.monitor import FileMonitor
27
- from autocoder.common.rulefiles.autocoderrules_utils import get_required_and_index_rules
28
- from autocoder.auto_coder_runner import load_tokenizer
29
- from autocoder.linters.shadow_linter import ShadowLinter
30
- from autocoder.compilers.shadow_compiler import ShadowCompiler
31
- from autocoder.shadows.shadow_manager import ShadowManager
26
+ from autocoder.common.rulefiles import get_required_and_index_rules, get_rules
32
27
  from autocoder.events.event_manager_singleton import get_event_manager
33
28
  from autocoder.events.event_types import Event, EventType, EventMetadata
34
29
  from autocoder.events import event_content as EventContentCreator
@@ -43,7 +38,8 @@ from .types import (
43
38
  BaseTool, ToolResult, AgentRequest, FileChangeEntry,
44
39
  LLMOutputEvent, LLMThinkingEvent, ToolCallEvent, ToolResultEvent,
45
40
  CompletionEvent, ErrorEvent, TokenUsageEvent, AttemptCompletionTool,
46
- PlanModeRespondTool,Message,ReplyDecision, PlanModeRespondEvent
41
+ PlanModeRespondTool, Message, ReplyDecision, PlanModeRespondEvent, RetryEvent,
42
+ AgenticEditConversationConfig, ConversationAction
47
43
  )
48
44
  from .tool_registry import ToolRegistry
49
45
  from .tools.base_tool_resolver import BaseToolResolver
@@ -54,6 +50,19 @@ from .agentic_tool_display import get_tool_display_message
54
50
  from autocoder.common.utils_code_auto_generate import stream_chat_with_continue
55
51
  from autocoder.common.save_formatted_log import save_formatted_log
56
52
  from . import agentic_lang
53
+ from autocoder.common.autocoderargs_parser import AutoCoderArgsParser
54
+ import importlib.resources as resources
55
+
56
+ def load_tokenizer():
57
+ from autocoder.rag.variable_holder import VariableHolder
58
+ from tokenizers import Tokenizer
59
+
60
+ try:
61
+ tokenizer_path = str(resources.files("autocoder") / "data" / "tokenizer.json")
62
+ VariableHolder.TOKENIZER_PATH = tokenizer_path
63
+ VariableHolder.TOKENIZER_MODEL = Tokenizer.from_file(tokenizer_path)
64
+ except FileNotFoundError:
65
+ tokenizer_path = None
57
66
 
58
67
  class BaseAgent(ABC):
59
68
  """
@@ -68,16 +77,29 @@ class BaseAgent(ABC):
68
77
  files: SourceCodeList,
69
78
  args: AutoCoderArgs,
70
79
  conversation_history: Optional[List[Dict[str, Any]]] = None,
71
- default_tools_list: Optional[List[str]] = None
80
+ default_tools_list: Optional[List[str]] = None,
81
+ custom_system_prompt: Optional[str] = None,
82
+ conversation_config: Optional['AgenticEditConversationConfig'] = None,
83
+ cancel_token: Optional[str] = None
72
84
  ):
85
+ # 并行执行相关初始化
86
+ self._parallel_executor = None
87
+ if getattr(args, 'enable_parallel_tools', False):
88
+ from concurrent.futures import ThreadPoolExecutor
89
+ self._parallel_executor = ThreadPoolExecutor(max_workers=4)
73
90
  """
74
91
  初始化代理
75
92
 
76
93
  Args:
94
+ name: 代理名称
77
95
  llm: 语言模型客户端
78
96
  files: 源码文件列表
79
97
  args: 配置参数
80
98
  conversation_history: 对话历史记录
99
+ default_tools_list: 默认工具列表
100
+ custom_system_prompt: 自定义系统提示
101
+ conversation_config: 对话配置
102
+ cancel_token: 取消令牌
81
103
  """
82
104
  # 1. 初始化FileMonitor(必须最先进行)
83
105
  try:
@@ -102,7 +124,17 @@ class BaseAgent(ABC):
102
124
  self.args = args
103
125
  self.files = files
104
126
  self.printer = Printer()
105
- self.conversation_history = conversation_history or []
127
+ # 对话历史存储优化:限制最大长度,实现LRU缓存
128
+ self.max_conversation_history = getattr(args, 'max_conversation_history', 20)
129
+ self.conversation_history = conversation_history[-self.max_conversation_history:] if conversation_history else []
130
+ self.conversation_config = conversation_config
131
+ self.cancel_token = cancel_token
132
+
133
+ # 内存监控
134
+ self._memory_warning_issued = False
135
+
136
+ # Initialize AutoCoderArgs parser for flexible parameter parsing
137
+ self.args_parser = AutoCoderArgsParser()
106
138
 
107
139
 
108
140
  # 5. 初始化其他组件
@@ -149,14 +181,25 @@ class BaseAgent(ABC):
149
181
  self.joined_groups: Dict[str, Group] = {}
150
182
  self.private_chats: Dict[str, List[Message]] = {}
151
183
  self.agentic_conversations: List[Dict[str,Any]] = []
152
- self.custom_system_prompt = "You are a highly skilled software engineer with extensive knowledge in many programming languages, frameworks, design patterns, and best practices."
184
+ self.custom_system_prompt = custom_system_prompt or "You are a highly skilled software engineer with extensive knowledge in many programming languages, frameworks, design patterns, and best practices."
153
185
  self.refuse_reply_reason = ""
154
186
  self._group_lock = threading.RLock() # 保护 joined_groups
155
187
  self._chat_lock = threading.RLock() # 保护 private_chats
156
188
  # 自动注册到AgentHub
157
189
  AgentHub.register_agent(self)
158
190
  register_default_tools(params=self._render_context(), default_tools_list=default_tools_list)
191
+
192
+ def _get_parsed_safe_zone_tokens(self) -> int:
193
+ """
194
+ 解析 conversation_prune_safe_zone_tokens 参数,支持多种格式
159
195
 
196
+ Returns:
197
+ 解析后的 token 数量
198
+ """
199
+ return self.args_parser.parse_conversation_prune_safe_zone_tokens(
200
+ self.args.conversation_prune_safe_zone_tokens,
201
+ self.args.code_model
202
+ )
160
203
 
161
204
  def who_am_i(self, role: str) -> 'BaseAgent':
162
205
  self.custom_system_prompt = role
@@ -393,41 +436,35 @@ class BaseAgent(ABC):
393
436
  """
394
437
  return self.file_changes
395
438
 
396
- def _get_changed_files_from_shadow(self) -> List[str]:
439
+ def get_all_file_changes(self) -> Dict[str, FileChangeEntry]:
397
440
  """
398
- 获取影子系统当前有哪些文件被修改或新增。
441
+ 获取当前记录的所有文件变更信息。
399
442
 
400
443
  Returns:
401
- 变更的文件路径列表
444
+ 字典,key 为文件路径,value 为变更详情
402
445
  """
403
- changed_files = []
404
- shadow_root = self.shadow_manager.shadows_dir
405
- for root, dirs, files in os.walk(shadow_root):
406
- for fname in files:
407
- shadow_file_path = os.path.join(root, fname)
408
- try:
409
- project_file_path = self.shadow_manager.from_shadow_path(
410
- shadow_file_path)
411
- rel_path = os.path.relpath(
412
- project_file_path, self.args.source_dir)
413
- changed_files.append(rel_path)
414
- except Exception:
415
- # 非映射关系,忽略
416
- continue
417
- return changed_files
446
+ return self.file_changes
418
447
 
419
448
 
449
+ # 缓存工具标签查找结果
450
+ _tool_tag_cache = {}
451
+
420
452
  def _reconstruct_tool_xml(self, tool: BaseTool) -> str:
421
453
  """
422
454
  Reconstructs the XML representation of a tool call from its Pydantic model.
423
455
  """
424
- tool_tag = next(
425
- (tag for tag, model in ToolRegistry.get_tag_model_map().items() if isinstance(tool, model)), None)
426
- if not tool_tag:
427
- logger.error(
428
- f"Cannot find tag name for tool type {type(tool).__name__}")
429
- # Return a placeholder or raise? Let's return an error XML string.
430
- return f"<error>Could not find tag for tool {type(tool).__name__}</error>"
456
+ tool_type = type(tool)
457
+ # 首先检查缓存
458
+ tool_tag = self._tool_tag_cache.get(tool_type)
459
+ if tool_tag is None:
460
+ tool_tag = next(
461
+ (tag for tag, model in ToolRegistry.get_tag_model_map().items() if tool_type is model), None)
462
+ if tool_tag:
463
+ self._tool_tag_cache[tool_type] = tool_tag
464
+ else:
465
+ logger.error(
466
+ f"Cannot find tag name for tool type {tool_type.__name__}")
467
+ return f"<error>Could not find tag for tool {tool_type.__name__}</error>"
431
468
 
432
469
  xml_parts = [f"<{tool_tag}>"]
433
470
  for field_name, field_value in tool.model_dump(exclude_none=True).items():
@@ -524,7 +561,7 @@ class BaseAgent(ABC):
524
561
  # Tool Use Guidelines
525
562
 
526
563
  1. In <thinking> tags, assess what information you already have and what information you need to proceed with the task.
527
- 2. Choose the most appropriate tool based on the task and the tool descriptions provided. Assess if you need additional information to proceed, and which of the available tools would be most effective for gathering this information. For example using the list_files tool is more effective than running a command like \`ls\` in the terminal. It's critical that you think about each available tool and use the one that best fits the current step in the task.
564
+ 2. Choose the most appropriate tool based on the task and the tool descriptions provided. Assess if you need additional information to proceed, and which of the available tools would be most effective for gathering this information. For example using the list_files tool is more effective than running a command like `ls` in the terminal. It's critical that you think about each available tool and use the one that best fits the current step in the task.
528
565
  3. If multiple actions are needed, use one tool at a time per message to accomplish the task iteratively, with each tool use being informed by the result of the previous tool use. Do not assume the outcome of any tool use. Each step must be informed by the previous step's result.
529
566
  4. Formulate your tool use using the XML format specified for each tool.
530
567
  5. After each tool use, the user will respond with the result of that tool use. This result will provide you with the necessary information to continue your task or make further decisions. This response may include:
@@ -595,9 +632,9 @@ class BaseAgent(ABC):
595
632
  RULES
596
633
 
597
634
  - Your current working directory is: {{current_project}}
598
- - You cannot \`cd\` into a different directory to complete a task. You are stuck operating from '{{ current_project }}', so be sure to pass in the correct 'path' parameter when using tools that require a path.
635
+ - You cannot `cd` into a different directory to complete a task. You are stuck operating from '{{ current_project }}', so be sure to pass in the correct 'path' parameter when using tools that require a path.
599
636
  - Do not use the ~ character or $HOME to refer to the home directory.
600
- - Before using the execute_command tool, you must first think about the SYSTEM INFORMATION context provided to understand the user's environment and tailor your commands to ensure they are compatible with their system. You must also consider if the command you need to run should be executed in a specific directory outside of the current working directory '{{ current_project }}', and if so prepend with \`cd\`'ing into that directory && then executing the command (as one command since you are stuck operating from '{{current_project}}'). For example, if you needed to run \`npm install\` in a project outside of '{{current_project}}', you would need to prepend with a \`cd\` i.e. pseudocode for this would be \`cd (path to project) && (command, in this case npm install)\`.
637
+ - Before using the execute_command tool, you must first think about the SYSTEM INFORMATION context provided to understand the user's environment and tailor your commands to ensure they are compatible with their system. You must also consider if the command you need to run should be executed in a specific directory outside of the current working directory '{{ current_project }}', and if so prepend with `cd`'ing into that directory && then executing the command (as one command since you are stuck operating from '{{current_project}}'). For example, if you needed to run `npm install` in a project outside of '{{current_project}}', you would need to prepend with a `cd` i.e. pseudocode for this would be `cd (path to project) && (command, in this case npm install)`.
601
638
  - When using the search_files tool, craft your regex patterns carefully to balance specificity and flexibility. Based on the user's task you may use it to find code patterns, TODO comments, function definitions, or any text-based information across the project. The results include context, so analyze the surrounding code to better understand the matches. Leverage the search_files tool in combination with other tools for more comprehensive analysis. For example, use it to find specific code patterns, then use read_file to examine the full context of interesting matches.
602
639
  - The write_to_file and replace_in_file tools are ONLY to be used for creating and updating research plans, search strategies, or summarizing findings. They are NOT to be used for modifying system files or any operational code.
603
640
  - When making research plans, always consider the context and objectives clearly outlined by the user.
@@ -625,15 +662,11 @@ class BaseAgent(ABC):
625
662
  RULES OR DOCUMENTS PROVIDED BY USER
626
663
 
627
664
  The following rules are provided by the user, and you must follow them strictly.
628
-
629
- <user_rule_or_document_files>
630
- {% for key, value in extra_docs.items() %}
631
- <user_rule_or_document_file>
665
+
666
+ {% for key, value in extra_docs.items() %}
632
667
  ##File: {{ key }}
633
- {{ value }}
634
- </user_rule_or_document_file>
635
- {% endfor %}
636
- </user_rule_or_document_files>
668
+ {{ value }}
669
+ {% endfor %}
637
670
 
638
671
  Make sure you always start your task by using the read_file tool to get the relevant RULE files listed in index.md based on the user's specific requirements.
639
672
  {% endif %}
@@ -719,7 +752,7 @@ class BaseAgent(ABC):
719
752
  "env_info": env_info,
720
753
  "shell_type": shell_type,
721
754
  "shell_encoding": shells.get_terminal_encoding(),
722
- "conversation_safe_zone_tokens": self.args.conversation_prune_safe_zone_tokens,
755
+ "conversation_safe_zone_tokens": self._get_parsed_safe_zone_tokens(),
723
756
  "os_distribution": shells.get_os_distribution(),
724
757
  "current_user": shells.get_current_username(),
725
758
  "current_project": os.path.abspath(self.args.source_dir),
@@ -754,6 +787,17 @@ class BaseAgent(ABC):
754
787
  conversations = [
755
788
  {"role": "system", "content": system_prompt},
756
789
  ]
790
+
791
+ # 恢复对话历史
792
+ if self.conversation_history:
793
+ logger.info(f"Restoring conversation history with {len(self.conversation_history)} messages")
794
+ for message in self.conversation_history:
795
+ # 确保消息格式正确(包含 role 和 content 字段)
796
+ if isinstance(message, dict) and 'role' in message and 'content' in message:
797
+ conversations.append({
798
+ "role": message['role'],
799
+ "content": message['content']
800
+ })
757
801
 
758
802
  conversations.append({
759
803
  "role": "user", "content": request.user_input
@@ -770,10 +814,13 @@ class BaseAgent(ABC):
770
814
  should_yield_completion_event = False
771
815
  completion_event = None
772
816
 
773
- while True:
817
+ # 更明确的循环条件,添加最大轮次检查
818
+ max_iterations = getattr(self.args, 'agentic_max_rounds', 20)
819
+ while iteration_count <= max_iterations:
774
820
  iteration_count += 1
775
- logger.info(f"Starting LLM interaction cycle #{iteration_count}")
776
- global_cancel.check_and_raise(token=self.args.event_file)
821
+ tool_executed = False
822
+ global_cancel.check_and_raise(token=self.cancel_token or self.args.cancel_token)
823
+
777
824
  last_message = conversations[-1]
778
825
  if last_message["role"] == "assistant":
779
826
  logger.info(f"Last message is assistant, skipping LLM interaction cycle")
@@ -785,12 +832,18 @@ class BaseAgent(ABC):
785
832
  ), completion_xml="")
786
833
  else:
787
834
  yield completion_event
788
- break
789
- logger.info(
790
- f"Starting LLM interaction cycle. History size: {len(conversations)}")
835
+ break
791
836
 
792
- assistant_buffer = ""
793
- logger.info("Initializing stream chat with LLM")
837
+ assistant_buffer = ""
838
+
839
+ # Check if we need to handle max rounds
840
+ if hasattr(self.args, 'agentic_max_rounds') and iteration_count > self.args.agentic_max_rounds:
841
+ logger.info(f"Agentic max rounds reached: {self.args.agentic_max_rounds}")
842
+ yield CompletionEvent(completion=AttemptCompletionTool(
843
+ result="Agentic max rounds reached, please try again later",
844
+ command=""
845
+ ), completion_xml="")
846
+ break
794
847
 
795
848
  ## 实际请求大模型
796
849
  llm_response_gen = stream_chat_with_continue(
@@ -800,37 +853,36 @@ class BaseAgent(ABC):
800
853
  args=self.args
801
854
  )
802
855
 
803
- logger.info("Starting to parse LLM response stream")
804
856
  parsed_events = self.stream_and_parse_llm_response(
805
857
  llm_response_gen)
806
858
 
807
859
  event_count = 0
808
860
  mark_event_should_finish = False
809
861
  for event in parsed_events:
862
+ global_cancel.check_and_raise(token=self.cancel_token or self.args.cancel_token)
810
863
  event_count += 1
811
- logger.info(f"Processing event #{event_count}: {type(event).__name__}")
812
- global_cancel.check_and_raise(token=self.args.event_file)
813
864
 
814
865
  if mark_event_should_finish:
815
866
  if isinstance(event, TokenUsageEvent):
816
- logger.info("Yielding token usage event")
817
867
  yield event
818
868
  continue
819
869
 
820
870
  if isinstance(event, (LLMOutputEvent, LLMThinkingEvent)):
821
- assistant_buffer += event.text
822
- logger.debug(f"Accumulated {len(assistant_buffer)} chars in assistant buffer")
823
- yield event # Yield text/thinking immediately for display
871
+ assistant_buffer += event.text
872
+ yield event # Yield text/thinking immediately for display
824
873
 
825
874
  elif isinstance(event, ToolCallEvent):
875
+
876
+ ## Check for background tasks notifications (basic implementation)
877
+ ## This is a simplified version compared to agentic_edit.py
878
+ ## Subclasses can override this for more sophisticated handling
879
+
826
880
  tool_executed = True
827
881
  tool_obj = event.tool
828
882
  tool_name = type(tool_obj).__name__
829
883
  logger.info(f"Tool call detected: {tool_name}")
830
884
  tool_xml = event.tool_xml # Already reconstructed by parser
831
885
 
832
- # Append assistant's thoughts and the tool call to history
833
- logger.info(f"Adding assistant message with tool call to conversation history")
834
886
  conversations.append({
835
887
  "role": "assistant",
836
888
  "content": assistant_buffer + tool_xml
@@ -838,29 +890,22 @@ class BaseAgent(ABC):
838
890
  assistant_buffer = "" # Reset buffer after tool call
839
891
 
840
892
  yield event # Yield the ToolCallEvent for display
841
- logger.info("Yielded ToolCallEvent")
842
893
 
843
894
  # Handle AttemptCompletion separately as it ends the loop
844
- if isinstance(tool_obj, AttemptCompletionTool):
845
- logger.info(
846
- "AttemptCompletionTool received. Finalizing session.")
847
- logger.info(f"Completion result: {tool_obj.result[:50]}...")
848
- completion_event = CompletionEvent(completion=tool_obj, completion_xml=tool_xml)
849
- logger.info(
850
- "Agentic analyze loop finished due to AttemptCompletion.")
851
- save_formatted_log(self.args.source_dir, json.dumps(conversations, ensure_ascii=False), "agentic_conversation")
895
+ if isinstance(tool_obj, AttemptCompletionTool):
896
+ completion_event = CompletionEvent(
897
+ completion=tool_obj, completion_xml=tool_xml)
898
+ save_formatted_log(self.args.source_dir, json.dumps(
899
+ conversations, ensure_ascii=False), "agentic_conversation")
852
900
  mark_event_should_finish = True
853
901
  should_yield_completion_event = True
854
902
  continue
855
903
 
856
- if isinstance(tool_obj, PlanModeRespondTool):
857
- logger.info(
858
- "PlanModeRespondTool received. Finalizing session.")
859
- logger.info(f"Plan mode response: {tool_obj.response[:50]}...")
904
+ if isinstance(tool_obj, PlanModeRespondTool):
860
905
  yield PlanModeRespondEvent(completion=tool_obj, completion_xml=tool_xml)
861
- logger.info(
862
- "AgenticEdit analyze loop finished due to PlanModeRespond.")
863
- save_formatted_log(self.args.source_dir, json.dumps(conversations, ensure_ascii=False), "agentic_conversation")
906
+ save_formatted_log(self.args.source_dir, json.dumps(
907
+ conversations, ensure_ascii=False), "agentic_conversation")
908
+ mark_event_should_finish = True
864
909
  continue
865
910
 
866
911
  # Resolve the tool
@@ -872,7 +917,7 @@ class BaseAgent(ABC):
872
917
  success=False, message="Error: Tool resolver not implemented.", content=None)
873
918
  result_event = ToolResultEvent(tool_name=type(
874
919
  tool_obj).__name__, result=tool_result)
875
- error_xml = f"<tool_result tool_name='{type(tool_obj).__name__}' success='false'><message>Error: Tool resolver not implemented.</message><content></content></tool_result>"
920
+ tool_executed_xml = f"<tool_result tool_name='{type(tool_obj).__name__}' success='false'><message>Error: Tool resolver not implemented.</message><content></content></tool_result>"
876
921
  else:
877
922
  try:
878
923
  logger.info(f"Creating resolver for tool: {tool_name}")
@@ -886,15 +931,13 @@ class BaseAgent(ABC):
886
931
  result_event = ToolResultEvent(tool_name=type(
887
932
  tool_obj).__name__, result=tool_result)
888
933
 
889
- # Prepare XML for conversation history
890
- logger.info("Preparing XML for conversation history")
891
934
  escaped_message = xml.sax.saxutils.escape(
892
935
  tool_result.message)
893
936
  content_str = str(
894
937
  tool_result.content) if tool_result.content is not None else ""
895
938
  escaped_content = xml.sax.saxutils.escape(
896
939
  content_str)
897
- error_xml = (
940
+ tool_executed_xml = (
898
941
  f"<tool_result tool_name='{type(tool_obj).__name__}' success='{str(tool_result.success).lower()}'>"
899
942
  f"<message>{escaped_message}</message>"
900
943
  f"<content>{escaped_content}</content>"
@@ -910,25 +953,23 @@ class BaseAgent(ABC):
910
953
  tool_obj).__name__, result=tool_result)
911
954
  escaped_error = xml.sax.saxutils.escape(
912
955
  error_message)
913
- error_xml = f"<tool_result tool_name='{type(tool_obj).__name__}' success='false'><message>{escaped_error}</message><content></content></tool_result>"
956
+ tool_executed_xml = f"<tool_result tool_name='{type(tool_obj).__name__}' success='false'><message>{escaped_error}</message><content></content></tool_result>"
914
957
 
915
- yield result_event # Yield the ToolResultEvent for display
916
- logger.info("Yielded ToolResultEvent")
958
+ yield result_event # Yield the ToolResultEvent for display
917
959
 
918
- # Append the tool result (as user message) to history
919
- logger.info("Adding tool result to conversation history")
960
+ # 添加工具结果到对话历史
920
961
  conversations.append({
921
962
  "role": "user", # Simulating the user providing the tool result
922
- "content": error_xml
963
+ "content": tool_executed_xml
923
964
  })
924
- logger.info(
925
- f"Added tool result to conversations for tool {type(tool_obj).__name__}")
926
- logger.info(f"Breaking LLM cycle after executing tool: {tool_name}")
927
-
965
+
928
966
  # 一次交互只能有一次工具,剩下的其实就没有用了,但是如果不让流式处理完,我们就无法获取服务端
929
967
  # 返回的token消耗和计费,所以通过此标记来完成进入空转,直到流式走完,获取到最后的token消耗和计费
930
- mark_event_should_finish = True
931
- # break # After tool execution and result, break to start a new LLM cycle
968
+ mark_event_should_finish = True
969
+
970
+ elif isinstance(event, RetryEvent):
971
+ logger.info(f"Retry event occurred: {event.message}")
972
+ yield event
932
973
 
933
974
  elif isinstance(event, ErrorEvent):
934
975
  logger.error(f"Error event occurred: {event.message}")
@@ -936,37 +977,38 @@ class BaseAgent(ABC):
936
977
  # Optionally stop the process on parsing errors
937
978
  # logger.error("Stopping analyze loop due to parsing error.")
938
979
  # return
939
- elif isinstance(event, TokenUsageEvent):
940
- logger.info("Yielding token usage event")
941
- yield event
980
+ elif isinstance(event, TokenUsageEvent):
981
+ yield event
942
982
 
943
983
  if not tool_executed:
944
984
  # No tool executed in this LLM response cycle
945
- logger.info("LLM response finished without executing a tool.")
985
+ logger.info("LLM response finished without executing a tool.")
946
986
  # Append any remaining assistant buffer to history if it wasn't followed by a tool
947
987
  if assistant_buffer:
948
- logger.info(f"Appending assistant buffer to history: {len(assistant_buffer)} chars")
988
+
949
989
  last_message = conversations[-1]
950
990
  if last_message["role"] != "assistant":
951
991
  logger.info("Adding new assistant message")
952
992
  conversations.append(
953
993
  {"role": "assistant", "content": assistant_buffer})
994
+
954
995
  elif last_message["role"] == "assistant":
955
996
  logger.info("Appending to existing assistant message")
956
997
  last_message["content"] += assistant_buffer
957
-
998
+
958
999
  # 添加系统提示,要求LLM必须使用工具或明确结束,而不是直接退出
959
- logger.info("Adding system reminder to use tools or attempt completion")
1000
+ logger.info(
1001
+ "Adding system reminder to use tools or attempt completion")
1002
+
960
1003
  conversations.append({
961
1004
  "role": "user",
962
1005
  "content": "NOTE: You must use an appropriate tool (such as read_file, write_to_file, execute_command, etc.) or explicitly complete the task (using attempt_completion). Do not provide text responses without taking concrete actions. Please select a suitable tool to continue based on the user's task."
963
1006
  })
964
- # 继续循环,让 LLM 再思考,而不是 break
965
- logger.info("Continuing the LLM interaction loop without breaking")
1007
+
966
1008
  continue
967
1009
 
968
- logger.info(f"Agentic analyze loop finished after {iteration_count} iterations.")
969
- save_formatted_log(self.args.source_dir, json.dumps(conversations, ensure_ascii=False), "agentic_conversation")
1010
+ logger.info(f"AgenticEdit analyze loop finished after {iteration_count} iterations.")
1011
+ save_formatted_log(self.args.source_dir, json.dumps(conversations, ensure_ascii=False), "agentic_conversation")
970
1012
 
971
1013
  def stream_and_parse_llm_response(
972
1014
  self, generator: Generator[Tuple[str, Any], None, None]
@@ -986,10 +1028,17 @@ class BaseAgent(ABC):
986
1028
  in_tool_block = False
987
1029
  in_thinking_block = False
988
1030
  current_tool_tag = None
989
- tool_start_pattern = re.compile(
990
- r"<([a-zA-Z0-9_]+)>") # Matches tool tags
1031
+
1032
+ # 预编译正则表达式以提高性能
1033
+ tool_start_pattern = re.compile(r"<([a-zA-Z0-9_]+)>")
1034
+ _tool_end_pattern = re.compile(r"</([a-zA-Z0-9_]+)>")
991
1035
  thinking_start_tag = "<thinking>"
992
1036
  thinking_end_tag = "</thinking>"
1037
+ _param_pattern = re.compile(r"<([a-zA-Z0-9_]+)>(.*?)</\1>", re.DOTALL)
1038
+
1039
+ # 性能监控
1040
+ start_time = time.time()
1041
+ event_count = 0
993
1042
 
994
1043
  def parse_tool_xml(tool_xml: str, tool_tag: str) -> Optional[BaseTool]:
995
1044
  """Minimal parser for tool XML string."""
@@ -1049,7 +1098,7 @@ class BaseAgent(ABC):
1049
1098
 
1050
1099
  last_metadata = None
1051
1100
  for content_chunk, metadata in generator:
1052
- global_cancel.check_and_raise(token=self.args.event_file)
1101
+ global_cancel.check_and_raise(token=self.cancel_token or self.args.cancel_token)
1053
1102
  if not content_chunk:
1054
1103
  last_metadata = metadata
1055
1104
  continue
@@ -1095,9 +1144,9 @@ class BaseAgent(ABC):
1095
1144
  else:
1096
1145
  yield ToolCallEvent(tool=tool_obj, tool_xml=reconstructed_xml)
1097
1146
  else:
1098
- yield ErrorEvent(message=f"Failed to parse tool: <{current_tool_tag}>")
1147
+ # yield ErrorEvent(message=f"Failed to parse tool: <{current_tool_tag}>")
1099
1148
  # Optionally yield the raw XML as plain text?
1100
- # yield LLMOutputEvent(text=tool_xml)
1149
+ yield LLMOutputEvent(text=f"Failed to parse tool: <{current_tool_tag}> {tool_xml}")
1101
1150
 
1102
1151
  buffer = buffer[tool_block_end_index:]
1103
1152
  in_tool_block = False
@@ -1170,19 +1219,25 @@ class BaseAgent(ABC):
1170
1219
  # After generator exhausted, yield any remaining content
1171
1220
  if in_thinking_block:
1172
1221
  # Unterminated thinking block
1173
- yield ErrorEvent(message="Stream ended with unterminated <thinking> block.")
1222
+ yield RetryEvent(message="Stream ended with unterminated <thinking> block.")
1174
1223
  if buffer:
1175
1224
  # Yield remaining as thinking
1176
1225
  yield LLMThinkingEvent(text=buffer)
1177
1226
  elif in_tool_block:
1178
1227
  # Unterminated tool block
1179
- yield ErrorEvent(message=f"Stream ended with unterminated <{current_tool_tag}> block.")
1228
+ yield RetryEvent(message=f"Stream ended with unterminated <{current_tool_tag}> block.")
1180
1229
  if buffer:
1181
1230
  yield LLMOutputEvent(text=buffer) # Yield remaining as text
1182
1231
  elif buffer:
1183
1232
  # Yield remaining plain text
1184
1233
  yield LLMOutputEvent(text=buffer)
1185
1234
 
1235
+ # 性能日志
1236
+ duration = time.time() - start_time
1237
+ logger.info(
1238
+ f"Event stream processing completed: {event_count} events in {duration:.3f}s "
1239
+ f"({event_count/max(duration, 0.001):.1f} events/sec)")
1240
+
1186
1241
  # 这个要放在最后,防止其他关联的多个事件的信息中断
1187
1242
  yield TokenUsageEvent(usage=last_metadata)
1188
1243
 
@@ -1243,20 +1298,48 @@ class BaseAgent(ABC):
1243
1298
  event_manager.write_result(
1244
1299
  content=content.to_dict(), metadata=metadata.to_dict())
1245
1300
  elif isinstance(agent_event, TokenUsageEvent):
1246
- # 获取模型信息以计算价格
1247
- model_name = ",".join(llms_utils.get_llm_names(self.llm))
1248
- model_info = llms_utils.get_model_info(
1249
- model_name, self.args.product_mode) or {}
1250
- input_price = model_info.get("input_price", 0.0) if model_info else 0.0
1251
- output_price = model_info.get("output_price", 0.0) if model_info else 0.0
1301
+ # 缓存模型价格信息
1302
+ if not hasattr(self, '_cached_model_info'):
1303
+ model_name = ",".join(llms_utils.get_llm_names(self.llm))
1304
+ self._cached_model_info = llms_utils.get_model_info(
1305
+ model_name, self.args.product_mode) or {}
1306
+ self._cached_model_name = model_name
1307
+
1308
+ # 获取价格
1309
+ input_price = self._cached_model_info.get("input_price", 0.0)
1310
+ output_price = self._cached_model_info.get("output_price", 0.0)
1252
1311
 
1253
1312
  # 计算成本
1254
1313
  last_meta = agent_event.usage
1255
- input_cost = (last_meta.input_tokens_count * input_price) / 1000000 # 转换为百万
1256
- output_cost = (last_meta.generated_tokens_count * output_price) / 1000000
1314
+ input_tokens = max(last_meta.input_tokens_count, 0)
1315
+ output_tokens = max(last_meta.generated_tokens_count, 0)
1316
+
1317
+ input_cost = (input_tokens * input_price) / 1000000 # 转换为百万
1318
+ output_cost = (output_tokens * output_price) / 1000000
1319
+
1320
+ # 预测总成本
1321
+ if not hasattr(self, '_total_input_tokens'):
1322
+ self._total_input_tokens = 0
1323
+ self._total_output_tokens = 0
1324
+ self._total_input_cost = 0.0
1325
+ self._total_output_cost = 0.0
1326
+
1327
+ self._total_input_tokens += input_tokens
1328
+ self._total_output_tokens += output_tokens
1329
+ self._total_input_cost += input_cost
1330
+ self._total_output_cost += output_cost
1257
1331
 
1258
- # 记录Token使用详情
1259
- logger.info(f"Token Usage Details: Model={model_name}, Input Tokens={last_meta.input_tokens_count}, Output Tokens={last_meta.generated_tokens_count}, Input Cost=${input_cost:.6f}, Output Cost=${output_cost:.6f}")
1332
+ # 记录详细Token使用情况
1333
+ logger.info(
1334
+ f"Token Usage Details:\n"
1335
+ f"- Model: {self._cached_model_name}\n"
1336
+ f"- Input: {input_tokens} tokens (${input_cost:.6f})\n"
1337
+ f"- Output: {output_tokens} tokens (${output_cost:.6f})\n"
1338
+ f"- Running Totals:\n"
1339
+ f" - Input: {self._total_input_tokens} tokens (${self._total_input_cost:.6f})\n"
1340
+ f" - Output: {self._total_output_tokens} tokens (${self._total_output_cost:.6f})\n"
1341
+ f"- Estimated Final Cost: ${(self._total_input_cost + self._total_output_cost) * 1.2:.6f} (with 20% buffer)"
1342
+ )
1260
1343
 
1261
1344
  # 写入Token统计事件
1262
1345
  get_event_manager(self.args.event_file).write_result(
@@ -1439,6 +1522,8 @@ class BaseAgent(ABC):
1439
1522
  yield ("result",event.completion.result)
1440
1523
  if event.completion.command:
1441
1524
  yield ("result", agentic_lang.get_message_with_format("suggested_command", command=event.completion.command))
1525
+ elif isinstance(event, RetryEvent):
1526
+ yield ("thinking", agentic_lang.get_message_with_format("retry_message", message=event.message))
1442
1527
  elif isinstance(event, ErrorEvent):
1443
1528
  yield ("result", agentic_lang.get_message("error_title"))
1444
1529
  yield ("result", agentic_lang.get_message_with_format("error_content", message=event.message))
@@ -1453,16 +1538,15 @@ class BaseAgent(ABC):
1453
1538
  finally:
1454
1539
  # 在结束时打印累计的token使用情况
1455
1540
  duration = time.time() - start_time
1456
- yield ("result","\n" + self.printer.get_message_from_key_with_format("code_generation_complete",
1457
- duration=duration,
1458
- input_tokens=total_input_tokens,
1459
- output_tokens=total_output_tokens,
1460
- input_cost=total_input_cost,
1461
- output_cost=total_output_cost,
1462
- speed=0.0,
1463
- model_names=model_name,
1464
- sampling_count=1))
1465
- yield ("result", "\n" + agentic_lang.get_message("agent_execution_complete"))
1541
+ # yield ("result","\n" + self.printer.get_message_from_key_with_format("code_generation_complete",
1542
+ # duration=duration,
1543
+ # input_tokens=total_input_tokens,
1544
+ # output_tokens=total_output_tokens,
1545
+ # input_cost=total_input_cost,
1546
+ # output_cost=total_output_cost,
1547
+ # speed=0.0,
1548
+ # model_names=model_name,
1549
+ # sampling_count=1))
1466
1550
 
1467
1551
  def run_in_terminal(self, request: AgentRequest):
1468
1552
  """
@@ -1746,4 +1830,19 @@ class BaseAgent(ABC):
1746
1830
  )
1747
1831
  else:
1748
1832
  self.printer.print_in_terminal("no_changes_made")
1749
-
1833
+
1834
+ @byzerllm.prompt(render="jinja2")
1835
+ def git_require_msg(self, source_dir: str, error: str) -> str:
1836
+ '''
1837
+ auto_merge only works for git repositories.
1838
+
1839
+ Try to use git init in the source directory.
1840
+
1841
+ ```shell
1842
+ cd {{ source_dir }}
1843
+ git init .
1844
+ ```
1845
+
1846
+ Then try to run auto-coder again.
1847
+ Error: {{ error }}
1848
+ '''