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
@@ -0,0 +1,665 @@
1
+ """
2
+ Subagent Workflow 执行器
3
+
4
+ 负责加载 workflow 配置、执行拓扑排序、运行各个步骤。
5
+ """
6
+
7
+ from pathlib import Path
8
+ from typing import Any, Dict, List, Optional, Set, Tuple
9
+ from copy import deepcopy
10
+ from concurrent.futures import ThreadPoolExecutor, as_completed
11
+ import json
12
+ from loguru import logger
13
+
14
+ from autocoder.common import AutoCoderArgs
15
+ from autocoder.common.agents import AgentManager, AgentParser
16
+ from autocoder.common.v2.agent.agentic_edit_types import (
17
+ AgenticEditConversationConfig,
18
+ ConversationAction,
19
+ )
20
+ from autocoder.common.conversations.get_conversation_manager import (
21
+ get_conversation_manager,
22
+ )
23
+ from autocoder.workflow_agents.types import (
24
+ WorkflowSpec,
25
+ StepSpec,
26
+ AgentSpec,
27
+ StepResult,
28
+ StepStatus,
29
+ WorkflowResult,
30
+ )
31
+ from autocoder.workflow_agents.agent import WorkflowSubAgent
32
+ from autocoder.workflow_agents.utils import (
33
+ render_template,
34
+ evaluate_condition,
35
+ extract_outputs,
36
+ )
37
+ from autocoder.workflow_agents.exceptions import (
38
+ WorkflowDependencyError,
39
+ WorkflowAgentNotFoundError,
40
+ WorkflowStepError,
41
+ WorkflowAgentDefinitionError,
42
+ )
43
+
44
+
45
+ class SubagentWorkflowExecutor:
46
+ """
47
+ Subagent Workflow 执行器
48
+
49
+ 负责编排和执行多个子代理,支持 DAG 拓扑排序、条件判断、输出映射等。
50
+ """
51
+
52
+ def __init__(
53
+ self,
54
+ workflow_spec: WorkflowSpec,
55
+ args: AutoCoderArgs,
56
+ llm: Any,
57
+ cancel_token: Optional[str] = None,
58
+ ) -> None:
59
+ """
60
+ 初始化执行器
61
+
62
+ Args:
63
+ workflow_spec: Workflow 规格配置
64
+ args: AutoCoderArgs 配置
65
+ llm: LLM 实例
66
+ cancel_token: 取消令牌,用于支持任务取消
67
+ """
68
+ self.workflow_spec = workflow_spec
69
+ self.args = args
70
+ self.llm = llm
71
+ self.cancel_token = cancel_token
72
+
73
+ # 解析配置
74
+ self.spec = workflow_spec.spec
75
+ self.agents: Dict[str, WorkflowSubAgent] = self._build_agents()
76
+ self.steps: List[StepSpec] = self.spec.steps
77
+
78
+ # 执行上下文
79
+ self.context: Dict[str, Any] = {
80
+ "vars": self.spec.vars,
81
+ "steps": {},
82
+ "_last_attempt_result": None,
83
+ }
84
+
85
+ # 会话管理(共享链路会话ID)
86
+ self._conversation_id: Optional[str] = None
87
+
88
+ # 执行结果
89
+ self.step_results: List[StepResult] = []
90
+
91
+ def _build_agents(self) -> Dict[str, WorkflowSubAgent]:
92
+ """
93
+ 构建代理字典
94
+
95
+ 使用 AgentManager 加载 agent 定义,获取 system prompt、model、include_rules 等信息
96
+
97
+ Returns:
98
+ 代理字典,key 为 agent_id
99
+ """
100
+ agents: Dict[str, WorkflowSubAgent] = {}
101
+ agent_manager = AgentManager(project_root=str(self.args.source_dir))
102
+
103
+ for agent_spec in self.spec.agents:
104
+ agent_definition = self._load_agent_definition(agent_spec, agent_manager)
105
+ agents[agent_spec.id] = self._create_sub_agent(agent_spec, agent_definition)
106
+
107
+ return agents
108
+
109
+ def _load_agent_definition(
110
+ self, agent_spec: AgentSpec, agent_manager: AgentManager
111
+ ) -> Tuple[str, Optional[str], bool]:
112
+ """
113
+ 加载 agent 定义
114
+
115
+ Args:
116
+ agent_spec: agent 规格
117
+ agent_manager: agent 管理器
118
+
119
+ Returns:
120
+ (system_prompt, model, include_rules)
121
+ """
122
+ agent_id = agent_spec.id
123
+ base_dir = Path(".autocoderagents")
124
+ prompt_path = base_dir / agent_spec.path
125
+
126
+ # 首先尝试从 AgentManager 获取
127
+ agent_definition = agent_manager.get_agent(agent_id)
128
+
129
+ if agent_definition:
130
+ logger.debug(
131
+ f"从 AgentManager 加载代理 {agent_id}: model={agent_definition.model}, include_rules={agent_definition.include_rules}"
132
+ )
133
+ return (
134
+ agent_definition.content,
135
+ agent_spec.model or agent_definition.model,
136
+ agent_definition.include_rules,
137
+ )
138
+
139
+ # 尝试直接解析文件
140
+ if prompt_path.exists():
141
+ try:
142
+ agent_definition = AgentParser.parse_agent_file(prompt_path)
143
+ logger.debug(f"从文件解析代理 {agent_id}: {prompt_path}")
144
+ return (
145
+ agent_definition.content,
146
+ agent_spec.model or agent_definition.model,
147
+ agent_definition.include_rules,
148
+ )
149
+ except Exception as e:
150
+ logger.warning(f"解析代理文件 {prompt_path} 失败: {e},使用纯文本内容")
151
+ return (
152
+ prompt_path.read_text(encoding="utf-8"),
153
+ agent_spec.model,
154
+ False,
155
+ )
156
+
157
+ # 文件不存在
158
+ logger.warning(f"代理 {agent_id} 的提示词文件不存在: {prompt_path}")
159
+ return ("", agent_spec.model, False)
160
+
161
+ def _create_sub_agent(
162
+ self, agent_spec: AgentSpec, agent_definition: Tuple[str, Optional[str], bool]
163
+ ) -> WorkflowSubAgent:
164
+ """
165
+ 创建子代理
166
+
167
+ Args:
168
+ agent_spec: agent 规格
169
+ agent_definition: (system_prompt, model, include_rules)
170
+
171
+ Returns:
172
+ WorkflowSubAgent 实例
173
+ """
174
+ system_prompt, model, include_rules = agent_definition
175
+
176
+ retry = (
177
+ agent_spec.retry
178
+ if agent_spec.retry is not None
179
+ else self.spec.globals.retries
180
+ )
181
+ timeout_sec = (
182
+ agent_spec.timeout_sec
183
+ if agent_spec.timeout_sec is not None
184
+ else self.spec.globals.timeout_sec
185
+ )
186
+
187
+ return WorkflowSubAgent(
188
+ agent_id=agent_spec.id,
189
+ model=model,
190
+ system_prompt=system_prompt,
191
+ retry=retry,
192
+ timeout_sec=timeout_sec,
193
+ runner_type=agent_spec.runner,
194
+ include_rules=include_rules,
195
+ )
196
+
197
+ def _toposort(self) -> List[StepSpec]:
198
+ """
199
+ 拓扑排序步骤
200
+
201
+ Returns:
202
+ 排序后的步骤列表
203
+
204
+ Raises:
205
+ WorkflowDependencyError: 如果检测到循环依赖或依赖不存在
206
+ """
207
+ result: List[StepSpec] = []
208
+ visited: Set[str] = set()
209
+ visiting: Set[str] = set()
210
+ id2step = {step.id: step for step in self.steps}
211
+
212
+ # 用于追踪依赖链
213
+ dependency_chain: List[str] = []
214
+
215
+ def dfs(step_id: str) -> None:
216
+ nonlocal dependency_chain
217
+
218
+ if step_id in visited:
219
+ return
220
+
221
+ if step_id in visiting:
222
+ # 循环依赖,构建依赖链
223
+ cycle_start = dependency_chain.index(step_id)
224
+ cycle = dependency_chain[cycle_start:] + [step_id]
225
+ raise WorkflowDependencyError(
226
+ message=f"检测到循环依赖", step_id=step_id, dependency_chain=cycle
227
+ )
228
+
229
+ visiting.add(step_id)
230
+ dependency_chain.append(step_id)
231
+
232
+ step = id2step[step_id]
233
+ for dep in step.needs:
234
+ if dep not in id2step:
235
+ all_step_ids = list(id2step.keys())
236
+ raise WorkflowDependencyError(
237
+ message=f"步骤 '{step_id}' 依赖不存在的步骤: '{dep}'",
238
+ step_id=step_id,
239
+ dependency_chain=[step_id, f"{dep} (不存在)"],
240
+ )
241
+ dfs(dep)
242
+
243
+ dependency_chain.pop()
244
+ visiting.remove(step_id)
245
+ visited.add(step_id)
246
+ result.append(step)
247
+
248
+ try:
249
+ for step in self.steps:
250
+ dependency_chain = [] # 重置依赖链
251
+ dfs(step.id)
252
+ except WorkflowDependencyError:
253
+ raise # 重新抛出我们自己的异常
254
+
255
+ return result
256
+
257
+ def _get_conversation_config(
258
+ self, step: StepSpec
259
+ ) -> Optional[AgenticEditConversationConfig]:
260
+ """按新语义仅基于 action 与可选 conversation_id 构造配置"""
261
+ action = self._get_action(step)
262
+ conversation_id = self._resolve_conversation_id(step, action)
263
+
264
+ return AgenticEditConversationConfig(
265
+ action=ConversationAction(action),
266
+ conversation_id=conversation_id,
267
+ )
268
+
269
+ def _get_action(self, step: StepSpec) -> str:
270
+ """读取动作,默认来源于全局 default_action"""
271
+ action = self.spec.conversation.default_action
272
+ if step.conversation is not None and step.conversation.action:
273
+ action = step.conversation.action
274
+ return action
275
+
276
+ def _resolve_conversation_id(self, step: StepSpec, action: str) -> Optional[str]:
277
+ """基于 action 与可选 conversation_id(支持模板渲染)获取会话ID"""
278
+ conversation_manager = get_conversation_manager()
279
+
280
+ # 1) 若步骤显式指定 conversation_id(需渲染),优先使用
281
+ explicit_id = None
282
+ if step.conversation is not None and step.conversation.conversation_id:
283
+ try:
284
+ explicit_id = str(
285
+ render_template(step.conversation.conversation_id, self.context)
286
+ )
287
+ except Exception:
288
+ explicit_id = step.conversation.conversation_id
289
+
290
+ if explicit_id:
291
+ # resume/continue/new 都可使用外部传入ID;new时若需要强制新建则忽略此ID
292
+ if action == "new":
293
+ # new 强制新建新会话并将其作为共享链路会话
294
+ self._conversation_id = conversation_manager.create_conversation(
295
+ name=self.workflow_spec.metadata.name,
296
+ description=self.workflow_spec.metadata.description,
297
+ )
298
+ conversation_manager.set_current_conversation(self._conversation_id)
299
+ return self._conversation_id
300
+ else:
301
+ # resume/continue 使用该ID,并设为共享链路会话
302
+ self._conversation_id = explicit_id
303
+ try:
304
+ conversation_manager.set_current_conversation(self._conversation_id)
305
+ except Exception:
306
+ # 若不存在,则按 resume 兜底:创建并设置
307
+ self._conversation_id = conversation_manager.create_conversation(
308
+ name=self.workflow_spec.metadata.name,
309
+ description=self.workflow_spec.metadata.description,
310
+ )
311
+ conversation_manager.set_current_conversation(self._conversation_id)
312
+ return self._conversation_id
313
+
314
+ # 2) 未显式指定ID,依据 action 与共享链路状态处理
315
+ if action == "new":
316
+ # 总是新建并重置共享链路
317
+ self._conversation_id = conversation_manager.create_conversation(
318
+ name=self.workflow_spec.metadata.name,
319
+ description=self.workflow_spec.metadata.description,
320
+ )
321
+ conversation_manager.set_current_conversation(self._conversation_id)
322
+ return self._conversation_id
323
+
324
+ # resume / continue:若已有共享ID则复用;否则从 current 获取,没有就新建
325
+ if self._conversation_id:
326
+ return self._conversation_id
327
+
328
+ current_id = conversation_manager.get_current_conversation_id()
329
+ if current_id:
330
+ self._conversation_id = current_id
331
+ return self._conversation_id
332
+
333
+ # 无当前会话则新建并设为当前
334
+ self._conversation_id = conversation_manager.create_conversation(
335
+ name=self.workflow_spec.metadata.name,
336
+ description=self.workflow_spec.metadata.description,
337
+ )
338
+ conversation_manager.set_current_conversation(self._conversation_id)
339
+ return self._conversation_id
340
+
341
+ def _get_shared_conversation_id(self, conversation_manager: Any) -> Optional[str]:
342
+ """兼容保留:不再使用 share_across_steps,内部转到 _resolve_conversation_id"""
343
+ return self._conversation_id
344
+
345
+ def run(self) -> WorkflowResult:
346
+ """
347
+ 执行 workflow
348
+
349
+ Returns:
350
+ WorkflowResult 对象,包含执行状态和所有步骤的结果
351
+ """
352
+ try:
353
+ sorted_steps = self._toposort()
354
+ except WorkflowDependencyError as e:
355
+ error_msg = str(e)
356
+ logger.error(error_msg)
357
+ return WorkflowResult(
358
+ success=False, context=self.context, step_results=[], error=error_msg
359
+ )
360
+ except Exception as e:
361
+ error_msg = f"拓扑排序失败: {str(e)}"
362
+ logger.error(error_msg, exc_info=True)
363
+ return WorkflowResult(
364
+ success=False, context=self.context, step_results=[], error=error_msg
365
+ )
366
+
367
+ logger.info(f"开始执行 workflow: {self.workflow_spec.metadata.name}")
368
+
369
+ for step in sorted_steps:
370
+ step_result = self._execute_step(step)
371
+ self.step_results.append(step_result)
372
+
373
+ # 如果步骤失败,可以选择是否继续(目前继续执行)
374
+ if step_result.status == StepStatus.FAILED:
375
+ logger.warning(f"步骤 {step.id} 失败,但继续执行后续步骤")
376
+
377
+ # 判断整体是否成功
378
+ failed_steps = [r for r in self.step_results if r.status == StepStatus.FAILED]
379
+ success = len(failed_steps) == 0
380
+
381
+ logger.info(
382
+ f"Workflow 执行完成: 总步骤={len(self.step_results)}, "
383
+ f"成功={len([r for r in self.step_results if r.status == StepStatus.SUCCESS])}, "
384
+ f"失败={len(failed_steps)}, "
385
+ f"跳过={len([r for r in self.step_results if r.status == StepStatus.SKIPPED])}"
386
+ )
387
+
388
+ return WorkflowResult(
389
+ success=success,
390
+ context=self.context,
391
+ step_results=self.step_results,
392
+ error=None if success else f"{len(failed_steps)} 个步骤失败",
393
+ )
394
+
395
+ def _execute_step(self, step: StepSpec) -> StepResult:
396
+ """
397
+ 执行单个步骤
398
+
399
+ Args:
400
+ step: 步骤规格
401
+
402
+ Returns:
403
+ StepResult 对象
404
+ """
405
+ logger.info(f"执行步骤: {step.id}")
406
+
407
+ # 评估条件
408
+ attempt_prev = self.context.get("_last_attempt_result")
409
+ if not evaluate_condition(step.when, attempt_prev, self.context):
410
+ logger.info(f"步骤 {step.id} 的条件不满足,跳过")
411
+ return StepResult(step_id=step.id, status=StepStatus.SKIPPED)
412
+
413
+ # 检查代理是否存在
414
+ agent_id = step.agent
415
+ if agent_id not in self.agents:
416
+ available_agents = list(self.agents.keys())
417
+ error = WorkflowAgentNotFoundError(
418
+ agent_id=agent_id, step_id=step.id, available_agents=available_agents
419
+ )
420
+ error_msg = str(error)
421
+ logger.error(error_msg)
422
+ return StepResult(
423
+ step_id=step.id, status=StepStatus.FAILED, error=error_msg
424
+ )
425
+
426
+ # 检查是否需要并行执行
427
+ if step.replicas > 1:
428
+ return self._execute_step_parallel(step)
429
+ else:
430
+ return self._execute_step_single(step)
431
+
432
+ def _execute_step_single(self, step: StepSpec) -> StepResult:
433
+ """
434
+ 执行单个步骤(非并行)
435
+
436
+ Args:
437
+ step: 步骤规格
438
+
439
+ Returns:
440
+ StepResult 对象
441
+ """
442
+ try:
443
+ # 渲染用户输入
444
+ user_input = render_template(
445
+ step.with_args.get("user_input", ""), self.context
446
+ )
447
+ if not isinstance(user_input, str):
448
+ user_input = str(user_input)
449
+
450
+ # 获取会话配置
451
+ conversation_config = self._get_conversation_config(step)
452
+
453
+ # 运行代理
454
+ agent = self.agents[step.agent]
455
+ completion = agent.run(
456
+ user_input=user_input,
457
+ conversation_config=conversation_config,
458
+ args=self.args,
459
+ llm=self.llm,
460
+ cancel_token=self.cancel_token,
461
+ )
462
+
463
+ # 处理结果
464
+ if completion is None:
465
+ error_msg = "代理未返回结果"
466
+ logger.warning(f"步骤 {step.id} {error_msg}")
467
+ return StepResult(
468
+ step_id=step.id, status=StepStatus.FAILED, error=error_msg
469
+ )
470
+
471
+ attempt_result = completion.result
472
+ logger.debug(f"步骤 {step.id} 完成,结果长度: {len(attempt_result)}")
473
+
474
+ self.context["_last_attempt_result"] = attempt_result
475
+
476
+ # 提取输出
477
+ outputs = extract_outputs(
478
+ outputs_map=step.outputs,
479
+ attempt_result=attempt_result,
480
+ attempt_format=self.spec.attempt.format,
481
+ default_jsonpaths=self.spec.attempt.jsonpaths,
482
+ context=self.context,
483
+ )
484
+
485
+ # 注入内置变量:conversation_id(强制覆盖以避免模板字面量泄漏)
486
+ outputs["conversation_id"] = self._conversation_id
487
+
488
+ # 保存到上下文
489
+ if step.id not in self.context["steps"]:
490
+ self.context["steps"][step.id] = {"outputs": {}}
491
+
492
+ self.context["steps"][step.id]["outputs"].update(outputs)
493
+ logger.debug(f"步骤 {step.id} 输出: {list(outputs.keys())}")
494
+
495
+ return StepResult(
496
+ step_id=step.id,
497
+ status=StepStatus.SUCCESS,
498
+ attempt_result=attempt_result,
499
+ outputs=outputs,
500
+ )
501
+
502
+ except Exception as e:
503
+ error_msg = f"执行异常: {str(e)}"
504
+ logger.error(f"步骤 {step.id} {error_msg}", exc_info=True)
505
+ return StepResult(
506
+ step_id=step.id, status=StepStatus.FAILED, error=error_msg
507
+ )
508
+
509
+ def _execute_step_parallel(self, step: StepSpec) -> StepResult:
510
+ """
511
+ 并行执行单个步骤的多个副本
512
+
513
+ Args:
514
+ step: 步骤规格
515
+
516
+ Returns:
517
+ StepResult 对象,包含合并后的结果
518
+ """
519
+ logger.info(f"步骤 {step.id} 将并行执行 {step.replicas} 个副本")
520
+
521
+ # 渲染用户输入(所有副本使用相同输入)
522
+ try:
523
+ user_input = render_template(
524
+ step.with_args.get("user_input", ""), self.context
525
+ )
526
+ if not isinstance(user_input, str):
527
+ user_input = str(user_input)
528
+ except Exception as e:
529
+ error_msg = f"渲染输入失败: {str(e)}"
530
+ logger.error(f"步骤 {step.id} {error_msg}", exc_info=True)
531
+ return StepResult(
532
+ step_id=step.id, status=StepStatus.FAILED, error=error_msg
533
+ )
534
+
535
+ # 并行执行所有副本
536
+ agent = self.agents[step.agent]
537
+ results = []
538
+ errors = []
539
+
540
+ def run_replica(replica_idx: int):
541
+ """运行单个副本"""
542
+ try:
543
+ logger.info(
544
+ f"步骤 {step.id} 副本 {replica_idx + 1}/{step.replicas} 开始执行"
545
+ )
546
+
547
+ # 获取会话配置(每个副本独立会话)
548
+ conversation_config = self._get_conversation_config(step)
549
+
550
+ # 运行代理
551
+ completion = agent.run(
552
+ user_input=user_input,
553
+ conversation_config=conversation_config,
554
+ args=self.args,
555
+ llm=self.llm,
556
+ cancel_token=self.cancel_token,
557
+ )
558
+
559
+ if completion is None:
560
+ return (replica_idx, None, "代理未返回结果")
561
+
562
+ logger.info(
563
+ f"步骤 {step.id} 副本 {replica_idx + 1}/{step.replicas} 执行完成"
564
+ )
565
+ return (replica_idx, completion.result, None)
566
+
567
+ except Exception as e:
568
+ error_msg = f"副本 {replica_idx + 1} 执行异常: {str(e)}"
569
+ logger.error(f"步骤 {step.id} {error_msg}", exc_info=True)
570
+ return (replica_idx, None, error_msg)
571
+
572
+ # 使用线程池并行执行
573
+ with ThreadPoolExecutor(max_workers=step.replicas) as executor:
574
+ futures = [executor.submit(run_replica, i) for i in range(step.replicas)]
575
+
576
+ for future in as_completed(futures):
577
+ replica_idx, result, error = future.result()
578
+ if error:
579
+ errors.append(f"副本 {replica_idx + 1}: {error}")
580
+ else:
581
+ results.append((replica_idx, result))
582
+
583
+ # 判断成功:任意一个成功即可(any-success 策略)
584
+ if not results:
585
+ # 全部失败
586
+ error_msg = f"所有 {step.replicas} 个副本都失败了: " + "; ".join(errors)
587
+ logger.error(f"步骤 {step.id} {error_msg}")
588
+ return StepResult(
589
+ step_id=step.id, status=StepStatus.FAILED, error=error_msg
590
+ )
591
+
592
+ # 至少有一个成功
593
+ logger.info(f"步骤 {step.id} 成功执行了 {len(results)}/{step.replicas} 个副本")
594
+
595
+ # 合并结果
596
+ merged_result = self._merge_replica_results(results, step)
597
+
598
+ # 更新上下文
599
+ self.context["_last_attempt_result"] = merged_result
600
+
601
+ # 提取输出(从合并后的结果中提取)
602
+ try:
603
+ outputs = extract_outputs(
604
+ outputs_map=step.outputs,
605
+ attempt_result=merged_result,
606
+ attempt_format=self.spec.attempt.format,
607
+ default_jsonpaths=self.spec.attempt.jsonpaths,
608
+ context=self.context,
609
+ )
610
+ except Exception as e:
611
+ logger.warning(f"步骤 {step.id} 提取输出失败: {e},使用空输出")
612
+ outputs = {}
613
+
614
+ # 注入内置变量:conversation_id
615
+ outputs["conversation_id"] = self._conversation_id
616
+
617
+ # 保存到上下文
618
+ if step.id not in self.context["steps"]:
619
+ self.context["steps"][step.id] = {"outputs": {}}
620
+
621
+ self.context["steps"][step.id]["outputs"].update(outputs)
622
+ logger.debug(f"步骤 {step.id} 输出: {list(outputs.keys())}")
623
+
624
+ return StepResult(
625
+ step_id=step.id,
626
+ status=StepStatus.SUCCESS,
627
+ attempt_result=merged_result,
628
+ outputs=outputs,
629
+ )
630
+
631
+ def _merge_replica_results(
632
+ self, results: List[Tuple[int, str]], step: StepSpec
633
+ ) -> str:
634
+ """
635
+ 合并多个副本的结果
636
+
637
+ Args:
638
+ results: [(replica_idx, attempt_result), ...]
639
+ step: 步骤规格
640
+
641
+ Returns:
642
+ 合并后的结果字符串
643
+ """
644
+ # 按副本索引排序
645
+ sorted_results = sorted(results, key=lambda x: x[0])
646
+ attempt_results = [result for _, result in sorted_results]
647
+
648
+ # 根据 attempt.format 决定合并方式
649
+ if self.spec.attempt.format == "json":
650
+ # JSON 格式:尝试将多个结果打包成 JSON 数组
651
+ json_objects = []
652
+ for result in attempt_results:
653
+ try:
654
+ obj = json.loads(result)
655
+ json_objects.append(obj)
656
+ except json.JSONDecodeError:
657
+ # 如果解析失败,保留原始字符串
658
+ json_objects.append({"raw": result})
659
+
660
+ # 返回 JSON 数组字符串
661
+ return json.dumps(json_objects, ensure_ascii=False, indent=2)
662
+ else:
663
+ # Text 格式:用分隔符拼接
664
+ separator = "\n---\n"
665
+ return separator.join(attempt_results)