auto-coder 1.0.0__py3-none-any.whl → 2.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of auto-coder might be problematic. Click here for more details.

Files changed (574) hide show
  1. auto_coder-2.0.0.dist-info/LICENSE +158 -0
  2. auto_coder-2.0.0.dist-info/METADATA +558 -0
  3. auto_coder-2.0.0.dist-info/RECORD +795 -0
  4. {auto_coder-1.0.0.dist-info → auto_coder-2.0.0.dist-info}/WHEEL +1 -1
  5. {auto_coder-1.0.0.dist-info → auto_coder-2.0.0.dist-info}/entry_points.txt +3 -3
  6. autocoder/__init__.py +31 -0
  7. autocoder/agent/auto_filegroup.py +32 -13
  8. autocoder/agent/auto_learn_from_commit.py +9 -1
  9. autocoder/agent/base_agentic/__init__.py +3 -0
  10. autocoder/agent/base_agentic/agent_hub.py +1 -1
  11. autocoder/agent/base_agentic/base_agent.py +235 -136
  12. autocoder/agent/base_agentic/default_tools.py +119 -118
  13. autocoder/agent/base_agentic/test_base_agent.py +1 -1
  14. autocoder/agent/base_agentic/tool_registry.py +32 -20
  15. autocoder/agent/base_agentic/tools/read_file_tool_resolver.py +24 -3
  16. autocoder/agent/base_agentic/tools/write_to_file_tool_resolver.py +24 -11
  17. autocoder/agent/base_agentic/types.py +42 -0
  18. autocoder/agent/entry_command_agent/chat.py +73 -59
  19. autocoder/auto_coder.py +31 -40
  20. autocoder/auto_coder_rag.py +11 -1084
  21. autocoder/auto_coder_runner.py +970 -2345
  22. autocoder/auto_coder_terminal.py +26 -0
  23. autocoder/auto_coder_terminal_v3.py +190 -0
  24. autocoder/chat/conf_command.py +224 -124
  25. autocoder/chat/models_command.py +361 -299
  26. autocoder/chat/rules_command.py +79 -31
  27. autocoder/chat_auto_coder.py +988 -398
  28. autocoder/chat_auto_coder_lang.py +23 -732
  29. autocoder/commands/auto_command.py +25 -8
  30. autocoder/commands/auto_web.py +1 -1
  31. autocoder/commands/tools.py +44 -44
  32. autocoder/common/__init__.py +150 -128
  33. autocoder/common/ac_style_command_parser/__init__.py +39 -2
  34. autocoder/common/ac_style_command_parser/config.py +422 -0
  35. autocoder/common/ac_style_command_parser/parser.py +292 -78
  36. autocoder/common/ac_style_command_parser/test_parser.py +241 -16
  37. autocoder/common/ac_style_command_parser/test_typed_parser.py +342 -0
  38. autocoder/common/ac_style_command_parser/typed_parser.py +653 -0
  39. autocoder/common/action_yml_file_manager.py +25 -13
  40. autocoder/common/agent_events/__init__.py +52 -0
  41. autocoder/common/agent_events/agent_event_emitter.py +193 -0
  42. autocoder/common/agent_events/event_factory.py +177 -0
  43. autocoder/common/agent_events/examples.py +307 -0
  44. autocoder/common/agent_events/types.py +113 -0
  45. autocoder/common/agent_events/utils.py +68 -0
  46. autocoder/common/agent_hooks/__init__.py +44 -0
  47. autocoder/common/agent_hooks/examples.py +582 -0
  48. autocoder/common/agent_hooks/hook_executor.py +217 -0
  49. autocoder/common/agent_hooks/hook_manager.py +288 -0
  50. autocoder/common/agent_hooks/types.py +133 -0
  51. autocoder/common/agent_hooks/utils.py +99 -0
  52. autocoder/common/agent_query_queue/queue_executor.py +324 -0
  53. autocoder/common/agent_query_queue/queue_manager.py +325 -0
  54. autocoder/common/agents/__init__.py +11 -0
  55. autocoder/common/agents/agent_manager.py +323 -0
  56. autocoder/common/agents/agent_parser.py +189 -0
  57. autocoder/common/agents/example_usage.py +344 -0
  58. autocoder/common/agents/integration_example.py +330 -0
  59. autocoder/common/agents/test_agent_parser.py +545 -0
  60. autocoder/common/async_utils.py +101 -0
  61. autocoder/common/auto_coder_lang.py +23 -972
  62. autocoder/common/autocoderargs_parser/__init__.py +14 -0
  63. autocoder/common/autocoderargs_parser/parser.py +184 -0
  64. autocoder/common/autocoderargs_parser/tests/__init__.py +1 -0
  65. autocoder/common/autocoderargs_parser/tests/test_args_parser.py +235 -0
  66. autocoder/common/autocoderargs_parser/tests/test_token_parser.py +195 -0
  67. autocoder/common/autocoderargs_parser/token_parser.py +290 -0
  68. autocoder/common/buildin_tokenizer.py +2 -4
  69. autocoder/common/code_auto_generate.py +149 -74
  70. autocoder/common/code_auto_generate_diff.py +163 -70
  71. autocoder/common/code_auto_generate_editblock.py +179 -89
  72. autocoder/common/code_auto_generate_strict_diff.py +167 -72
  73. autocoder/common/code_auto_merge_editblock.py +13 -6
  74. autocoder/common/code_modification_ranker.py +1 -1
  75. autocoder/common/command_completer.py +3 -3
  76. autocoder/common/command_file_manager/manager.py +183 -47
  77. autocoder/common/command_file_manager/test_command_file_manager.py +507 -0
  78. autocoder/common/command_templates.py +1 -1
  79. autocoder/common/conf_utils.py +2 -4
  80. autocoder/common/conversations/config.py +11 -3
  81. autocoder/common/conversations/get_conversation_manager.py +100 -2
  82. autocoder/common/conversations/llm_stats_models.py +264 -0
  83. autocoder/common/conversations/manager.py +112 -28
  84. autocoder/common/conversations/models.py +16 -2
  85. autocoder/common/conversations/storage/index_manager.py +134 -10
  86. autocoder/common/core_config/__init__.py +63 -0
  87. autocoder/common/core_config/agentic_mode_manager.py +109 -0
  88. autocoder/common/core_config/base_manager.py +123 -0
  89. autocoder/common/core_config/compatibility.py +151 -0
  90. autocoder/common/core_config/config_manager.py +156 -0
  91. autocoder/common/core_config/conversation_manager.py +31 -0
  92. autocoder/common/core_config/exclude_manager.py +72 -0
  93. autocoder/common/core_config/file_manager.py +177 -0
  94. autocoder/common/core_config/human_as_model_manager.py +129 -0
  95. autocoder/common/core_config/lib_manager.py +54 -0
  96. autocoder/common/core_config/main_manager.py +81 -0
  97. autocoder/common/core_config/mode_manager.py +126 -0
  98. autocoder/common/core_config/models.py +70 -0
  99. autocoder/common/core_config/test_memory_manager.py +1056 -0
  100. autocoder/common/env_manager.py +282 -0
  101. autocoder/common/env_manager_usage_example.py +211 -0
  102. autocoder/common/file_checkpoint/conversation_checkpoint.py +19 -19
  103. autocoder/common/file_checkpoint/manager.py +264 -48
  104. autocoder/common/file_checkpoint/test_backup.py +1 -18
  105. autocoder/common/file_checkpoint/test_manager.py +270 -1
  106. autocoder/common/file_checkpoint/test_store.py +1 -17
  107. autocoder/common/file_handler/__init__.py +23 -0
  108. autocoder/common/file_handler/active_context_handler.py +159 -0
  109. autocoder/common/file_handler/add_files_handler.py +409 -0
  110. autocoder/common/file_handler/chat_handler.py +180 -0
  111. autocoder/common/file_handler/coding_handler.py +401 -0
  112. autocoder/common/file_handler/commit_handler.py +200 -0
  113. autocoder/common/file_handler/lib_handler.py +156 -0
  114. autocoder/common/file_handler/list_files_handler.py +111 -0
  115. autocoder/common/file_handler/mcp_handler.py +268 -0
  116. autocoder/common/file_handler/models_handler.py +493 -0
  117. autocoder/common/file_handler/remove_files_handler.py +172 -0
  118. autocoder/common/git_utils.py +44 -8
  119. autocoder/common/global_cancel.py +15 -6
  120. autocoder/common/ignorefiles/test_ignore_file_utils.py +1 -1
  121. autocoder/common/international/__init__.py +31 -0
  122. autocoder/common/international/demo_international.py +92 -0
  123. autocoder/common/international/message_manager.py +157 -0
  124. autocoder/common/international/messages/__init__.py +56 -0
  125. autocoder/common/international/messages/async_command_messages.py +507 -0
  126. autocoder/common/international/messages/auto_coder_messages.py +2208 -0
  127. autocoder/common/international/messages/chat_auto_coder_messages.py +1547 -0
  128. autocoder/common/international/messages/command_help_messages.py +986 -0
  129. autocoder/common/international/messages/conversation_command_messages.py +191 -0
  130. autocoder/common/international/messages/git_helper_plugin_messages.py +159 -0
  131. autocoder/common/international/messages/queue_command_messages.py +751 -0
  132. autocoder/common/international/messages/rules_command_messages.py +77 -0
  133. autocoder/common/international/messages/sdk_messages.py +1707 -0
  134. autocoder/common/international/messages/token_helper_plugin_messages.py +361 -0
  135. autocoder/common/international/messages/tool_display_messages.py +1212 -0
  136. autocoder/common/international/messages/workflow_exception_messages.py +473 -0
  137. autocoder/common/international/test_international.py +612 -0
  138. autocoder/common/linter_core/__init__.py +28 -0
  139. autocoder/common/linter_core/base_linter.py +61 -0
  140. autocoder/common/linter_core/config_loader.py +271 -0
  141. autocoder/common/linter_core/formatters/__init__.py +0 -0
  142. autocoder/common/linter_core/formatters/base_formatter.py +38 -0
  143. autocoder/common/linter_core/formatters/raw_formatter.py +17 -0
  144. autocoder/common/linter_core/linter.py +166 -0
  145. autocoder/common/linter_core/linter_factory.py +216 -0
  146. autocoder/common/linter_core/linter_manager.py +333 -0
  147. autocoder/common/linter_core/linters/__init__.py +9 -0
  148. autocoder/common/linter_core/linters/java_linter.py +342 -0
  149. autocoder/common/linter_core/linters/python_linter.py +115 -0
  150. autocoder/common/linter_core/linters/typescript_linter.py +119 -0
  151. autocoder/common/linter_core/models/__init__.py +7 -0
  152. autocoder/common/linter_core/models/lint_result.py +91 -0
  153. autocoder/common/linter_core/models.py +33 -0
  154. autocoder/common/linter_core/tests/__init__.py +3 -0
  155. autocoder/common/linter_core/tests/test_config_loader.py +323 -0
  156. autocoder/common/linter_core/tests/test_config_loading.py +308 -0
  157. autocoder/common/linter_core/tests/test_factory_manager.py +234 -0
  158. autocoder/common/linter_core/tests/test_formatters.py +147 -0
  159. autocoder/common/linter_core/tests/test_integration.py +317 -0
  160. autocoder/common/linter_core/tests/test_java_linter.py +496 -0
  161. autocoder/common/linter_core/tests/test_linters.py +265 -0
  162. autocoder/common/linter_core/tests/test_models.py +81 -0
  163. autocoder/common/linter_core/tests/verify_config_loading.py +296 -0
  164. autocoder/common/linter_core/tests/verify_fixes.py +183 -0
  165. autocoder/common/llm_friendly_package/__init__.py +31 -0
  166. autocoder/common/llm_friendly_package/base_manager.py +102 -0
  167. autocoder/common/llm_friendly_package/docs_manager.py +121 -0
  168. autocoder/common/llm_friendly_package/library_manager.py +171 -0
  169. autocoder/common/{llm_friendly_package.py → llm_friendly_package/main_manager.py} +204 -231
  170. autocoder/common/llm_friendly_package/models.py +40 -0
  171. autocoder/common/llm_friendly_package/test_llm_friendly_package.py +536 -0
  172. autocoder/common/llms/__init__.py +15 -0
  173. autocoder/common/llms/demo_error_handling.py +85 -0
  174. autocoder/common/llms/factory.py +142 -0
  175. autocoder/common/llms/manager.py +264 -0
  176. autocoder/common/llms/pricing.py +121 -0
  177. autocoder/common/llms/registry.py +288 -0
  178. autocoder/common/llms/schema.py +77 -0
  179. autocoder/common/llms/simple_demo.py +45 -0
  180. autocoder/common/llms/test_quick_model.py +116 -0
  181. autocoder/common/llms/test_remove_functionality.py +182 -0
  182. autocoder/common/llms/tests/__init__.py +1 -0
  183. autocoder/common/llms/tests/test_manager.py +330 -0
  184. autocoder/common/llms/tests/test_registry.py +364 -0
  185. autocoder/common/mcp_tools/__init__.py +62 -0
  186. autocoder/common/{mcp_tools.py → mcp_tools/executor.py} +49 -40
  187. autocoder/common/{mcp_hub.py → mcp_tools/hub.py} +42 -68
  188. autocoder/common/{mcp_server_install.py → mcp_tools/installer.py} +16 -28
  189. autocoder/common/{mcp_server.py → mcp_tools/server.py} +176 -48
  190. autocoder/common/mcp_tools/test_keyboard_interrupt.py +93 -0
  191. autocoder/common/mcp_tools/test_mcp_tools.py +391 -0
  192. autocoder/common/{mcp_server_types.py → mcp_tools/types.py} +121 -48
  193. autocoder/common/mcp_tools/verify_functionality.py +202 -0
  194. autocoder/common/model_speed_tester.py +32 -26
  195. autocoder/common/priority_directory_finder/__init__.py +142 -0
  196. autocoder/common/priority_directory_finder/examples.py +230 -0
  197. autocoder/common/priority_directory_finder/finder.py +283 -0
  198. autocoder/common/priority_directory_finder/models.py +236 -0
  199. autocoder/common/priority_directory_finder/test_priority_directory_finder.py +431 -0
  200. autocoder/common/project_scanner/__init__.py +18 -0
  201. autocoder/common/project_scanner/compat.py +77 -0
  202. autocoder/common/project_scanner/scanner.py +436 -0
  203. autocoder/common/project_tracker/__init__.py +27 -0
  204. autocoder/common/project_tracker/api.py +228 -0
  205. autocoder/common/project_tracker/demo.py +272 -0
  206. autocoder/common/project_tracker/tracker.py +487 -0
  207. autocoder/common/project_tracker/types.py +53 -0
  208. autocoder/common/pruner/__init__.py +67 -0
  209. autocoder/common/pruner/agentic_conversation_pruner.py +651 -102
  210. autocoder/common/pruner/conversation_message_ids_api.py +386 -0
  211. autocoder/common/pruner/conversation_message_ids_manager.py +347 -0
  212. autocoder/common/pruner/conversation_message_ids_pruner.py +473 -0
  213. autocoder/common/pruner/conversation_normalizer.py +347 -0
  214. autocoder/common/pruner/conversation_pruner.py +26 -6
  215. autocoder/common/pruner/test_agentic_conversation_pruner.py +554 -112
  216. autocoder/common/pruner/test_conversation_normalizer.py +502 -0
  217. autocoder/common/pruner/test_tool_content_detector.py +324 -0
  218. autocoder/common/pruner/tool_content_detector.py +227 -0
  219. autocoder/common/pruner/tools/__init__.py +18 -0
  220. autocoder/common/pruner/tools/query_message_ids.py +264 -0
  221. autocoder/common/pruner/tools/test_agentic_pruning_logic.py +432 -0
  222. autocoder/common/pruner/tools/test_message_ids_pruning_only.py +192 -0
  223. autocoder/common/pull_requests/__init__.py +9 -1
  224. autocoder/common/pull_requests/utils.py +122 -1
  225. autocoder/common/rag_manager/rag_manager.py +36 -40
  226. autocoder/common/rulefiles/__init__.py +53 -1
  227. autocoder/common/rulefiles/api.py +250 -0
  228. autocoder/common/rulefiles/core/__init__.py +14 -0
  229. autocoder/common/rulefiles/core/manager.py +241 -0
  230. autocoder/common/rulefiles/core/selector.py +805 -0
  231. autocoder/common/rulefiles/models/__init__.py +20 -0
  232. autocoder/common/rulefiles/models/index.py +16 -0
  233. autocoder/common/rulefiles/models/init_rule.py +18 -0
  234. autocoder/common/rulefiles/models/rule_file.py +18 -0
  235. autocoder/common/rulefiles/models/rule_relevance.py +14 -0
  236. autocoder/common/rulefiles/models/summary.py +16 -0
  237. autocoder/common/rulefiles/test_rulefiles.py +776 -0
  238. autocoder/common/rulefiles/utils/__init__.py +34 -0
  239. autocoder/common/rulefiles/utils/monitor.py +86 -0
  240. autocoder/common/rulefiles/utils/parser.py +230 -0
  241. autocoder/common/save_formatted_log.py +67 -10
  242. autocoder/common/search_replace.py +8 -1
  243. autocoder/common/search_replace_patch/__init__.py +24 -0
  244. autocoder/common/search_replace_patch/base.py +115 -0
  245. autocoder/common/search_replace_patch/manager.py +248 -0
  246. autocoder/common/search_replace_patch/patch_replacer.py +304 -0
  247. autocoder/common/search_replace_patch/similarity_replacer.py +306 -0
  248. autocoder/common/search_replace_patch/string_replacer.py +181 -0
  249. autocoder/common/search_replace_patch/tests/__init__.py +3 -0
  250. autocoder/common/search_replace_patch/tests/run_tests.py +126 -0
  251. autocoder/common/search_replace_patch/tests/test_base.py +188 -0
  252. autocoder/common/search_replace_patch/tests/test_empty_line_insert.py +233 -0
  253. autocoder/common/search_replace_patch/tests/test_integration.py +389 -0
  254. autocoder/common/search_replace_patch/tests/test_manager.py +351 -0
  255. autocoder/common/search_replace_patch/tests/test_patch_replacer.py +316 -0
  256. autocoder/common/search_replace_patch/tests/test_regex_replacer.py +306 -0
  257. autocoder/common/search_replace_patch/tests/test_similarity_replacer.py +384 -0
  258. autocoder/common/shell_commands/__init__.py +197 -0
  259. autocoder/common/shell_commands/background_process_notifier.py +346 -0
  260. autocoder/common/shell_commands/command_executor.py +1127 -0
  261. autocoder/common/shell_commands/error_recovery.py +541 -0
  262. autocoder/common/shell_commands/exceptions.py +120 -0
  263. autocoder/common/shell_commands/interactive_executor.py +476 -0
  264. autocoder/common/shell_commands/interactive_pexpect_process.py +623 -0
  265. autocoder/common/shell_commands/interactive_process.py +744 -0
  266. autocoder/common/shell_commands/interactive_session_manager.py +1014 -0
  267. autocoder/common/shell_commands/monitoring.py +529 -0
  268. autocoder/common/shell_commands/process_cleanup.py +386 -0
  269. autocoder/common/shell_commands/process_manager.py +606 -0
  270. autocoder/common/shell_commands/test_interactive_pexpect_process.py +281 -0
  271. autocoder/common/shell_commands/tests/__init__.py +6 -0
  272. autocoder/common/shell_commands/tests/conftest.py +118 -0
  273. autocoder/common/shell_commands/tests/test_background_process_notifier.py +703 -0
  274. autocoder/common/shell_commands/tests/test_command_executor.py +448 -0
  275. autocoder/common/shell_commands/tests/test_error_recovery.py +305 -0
  276. autocoder/common/shell_commands/tests/test_exceptions.py +299 -0
  277. autocoder/common/shell_commands/tests/test_execute_batch.py +588 -0
  278. autocoder/common/shell_commands/tests/test_indented_batch_commands.py +244 -0
  279. autocoder/common/shell_commands/tests/test_integration.py +664 -0
  280. autocoder/common/shell_commands/tests/test_monitoring.py +546 -0
  281. autocoder/common/shell_commands/tests/test_performance.py +632 -0
  282. autocoder/common/shell_commands/tests/test_process_cleanup.py +397 -0
  283. autocoder/common/shell_commands/tests/test_process_manager.py +606 -0
  284. autocoder/common/shell_commands/tests/test_timeout_config.py +343 -0
  285. autocoder/common/shell_commands/tests/test_timeout_manager.py +520 -0
  286. autocoder/common/shell_commands/timeout_config.py +315 -0
  287. autocoder/common/shell_commands/timeout_manager.py +352 -0
  288. autocoder/common/terminal_paste/__init__.py +14 -0
  289. autocoder/common/terminal_paste/demo.py +145 -0
  290. autocoder/common/terminal_paste/demo_paste_functionality.py +95 -0
  291. autocoder/common/terminal_paste/paste_handler.py +200 -0
  292. autocoder/common/terminal_paste/paste_manager.py +118 -0
  293. autocoder/common/terminal_paste/tests/__init__.py +1 -0
  294. autocoder/common/terminal_paste/tests/test_paste_handler.py +182 -0
  295. autocoder/common/terminal_paste/tests/test_paste_manager.py +126 -0
  296. autocoder/common/terminal_paste/utils.py +163 -0
  297. autocoder/common/test_autocoder_args.py +232 -0
  298. autocoder/common/test_env_manager.py +173 -0
  299. autocoder/common/test_env_manager_integration.py +159 -0
  300. autocoder/common/text_similarity/__init__.py +9 -0
  301. autocoder/common/text_similarity/demo.py +216 -0
  302. autocoder/common/text_similarity/examples.py +266 -0
  303. autocoder/common/text_similarity/test_text_similarity.py +306 -0
  304. autocoder/common/text_similarity/text_similarity.py +194 -0
  305. autocoder/common/text_similarity/utils.py +125 -0
  306. autocoder/common/todos/__init__.py +61 -0
  307. autocoder/common/todos/cache/__init__.py +16 -0
  308. autocoder/common/todos/cache/base_cache.py +89 -0
  309. autocoder/common/todos/cache/cache_manager.py +228 -0
  310. autocoder/common/todos/cache/memory_cache.py +225 -0
  311. autocoder/common/todos/config.py +155 -0
  312. autocoder/common/todos/exceptions.py +35 -0
  313. autocoder/common/todos/get_todo_manager.py +161 -0
  314. autocoder/common/todos/manager.py +537 -0
  315. autocoder/common/todos/models.py +239 -0
  316. autocoder/common/todos/storage/__init__.py +14 -0
  317. autocoder/common/todos/storage/base_storage.py +76 -0
  318. autocoder/common/todos/storage/file_storage.py +278 -0
  319. autocoder/common/tokens/counter.py +24 -2
  320. autocoder/common/tools_manager/__init__.py +17 -0
  321. autocoder/common/tools_manager/examples.py +162 -0
  322. autocoder/common/tools_manager/manager.py +385 -0
  323. autocoder/common/tools_manager/models.py +39 -0
  324. autocoder/common/tools_manager/test_tools_manager.py +303 -0
  325. autocoder/common/tools_manager/utils.py +191 -0
  326. autocoder/common/v2/agent/agentic_callbacks.py +270 -0
  327. autocoder/common/v2/agent/agentic_edit.py +2699 -1856
  328. autocoder/common/v2/agent/agentic_edit_change_manager.py +474 -0
  329. autocoder/common/v2/agent/agentic_edit_tools/__init__.py +35 -1
  330. autocoder/common/v2/agent/agentic_edit_tools/ac_mod_list_tool_resolver.py +279 -0
  331. autocoder/common/v2/agent/agentic_edit_tools/ac_mod_write_tool_resolver.py +10 -1
  332. autocoder/common/v2/agent/agentic_edit_tools/background_task_tool_resolver.py +1167 -0
  333. autocoder/common/v2/agent/agentic_edit_tools/base_tool_resolver.py +2 -2
  334. autocoder/common/v2/agent/agentic_edit_tools/conversation_message_ids_read_tool_resolver.py +214 -0
  335. autocoder/common/v2/agent/agentic_edit_tools/conversation_message_ids_write_tool_resolver.py +299 -0
  336. autocoder/common/v2/agent/agentic_edit_tools/count_tokens_tool_resolver.py +290 -0
  337. autocoder/common/v2/agent/agentic_edit_tools/execute_command_tool_resolver.py +564 -29
  338. autocoder/common/v2/agent/agentic_edit_tools/execute_workflow_tool_resolver.py +485 -0
  339. autocoder/common/v2/agent/agentic_edit_tools/extract_to_text_tool_resolver.py +225 -0
  340. autocoder/common/v2/agent/agentic_edit_tools/lint_report.py +79 -0
  341. autocoder/common/v2/agent/agentic_edit_tools/linter_config_models.py +343 -0
  342. autocoder/common/v2/agent/agentic_edit_tools/linter_enabled_tool_resolver.py +189 -0
  343. autocoder/common/v2/agent/agentic_edit_tools/list_files_tool_resolver.py +169 -101
  344. autocoder/common/v2/agent/agentic_edit_tools/load_extra_document_tool_resolver.py +349 -0
  345. autocoder/common/v2/agent/agentic_edit_tools/read_file_tool_resolver.py +243 -50
  346. autocoder/common/v2/agent/agentic_edit_tools/replace_in_file_tool_resolver.py +667 -147
  347. autocoder/common/v2/agent/agentic_edit_tools/run_named_subagents_tool_resolver.py +691 -0
  348. autocoder/common/v2/agent/agentic_edit_tools/search_files_tool_resolver.py +410 -86
  349. autocoder/common/v2/agent/agentic_edit_tools/session_interactive_tool_resolver.py +115 -0
  350. autocoder/common/v2/agent/agentic_edit_tools/session_start_tool_resolver.py +190 -0
  351. autocoder/common/v2/agent/agentic_edit_tools/session_stop_tool_resolver.py +76 -0
  352. autocoder/common/v2/agent/agentic_edit_tools/test_write_to_file_tool_resolver.py +207 -192
  353. autocoder/common/v2/agent/agentic_edit_tools/todo_read_tool_resolver.py +80 -63
  354. autocoder/common/v2/agent/agentic_edit_tools/todo_write_tool_resolver.py +237 -233
  355. autocoder/common/v2/agent/agentic_edit_tools/use_mcp_tool_resolver.py +2 -2
  356. autocoder/common/v2/agent/agentic_edit_tools/web_crawl_tool_resolver.py +557 -0
  357. autocoder/common/v2/agent/agentic_edit_tools/web_search_tool_resolver.py +600 -0
  358. autocoder/common/v2/agent/agentic_edit_tools/write_to_file_tool_resolver.py +56 -121
  359. autocoder/common/v2/agent/agentic_edit_types.py +343 -9
  360. autocoder/common/v2/agent/runner/__init__.py +3 -3
  361. autocoder/common/v2/agent/runner/base_runner.py +12 -26
  362. autocoder/common/v2/agent/runner/{event_runner.py → file_based_event_runner.py} +3 -2
  363. autocoder/common/v2/agent/runner/sdk_runner.py +150 -8
  364. autocoder/common/v2/agent/runner/terminal_runner.py +170 -57
  365. autocoder/common/v2/agent/runner/tool_display.py +557 -159
  366. autocoder/common/v2/agent/test_agentic_callbacks.py +265 -0
  367. autocoder/common/v2/agent/test_agentic_edit.py +194 -0
  368. autocoder/common/v2/agent/tool_caller/__init__.py +24 -0
  369. autocoder/common/v2/agent/tool_caller/default_tool_resolver_map.py +135 -0
  370. autocoder/common/v2/agent/tool_caller/integration_test.py +172 -0
  371. autocoder/common/v2/agent/tool_caller/plugins/__init__.py +14 -0
  372. autocoder/common/v2/agent/tool_caller/plugins/base_plugin.py +126 -0
  373. autocoder/common/v2/agent/tool_caller/plugins/examples/__init__.py +13 -0
  374. autocoder/common/v2/agent/tool_caller/plugins/examples/logging_plugin.py +164 -0
  375. autocoder/common/v2/agent/tool_caller/plugins/examples/security_filter_plugin.py +198 -0
  376. autocoder/common/v2/agent/tool_caller/plugins/plugin_interface.py +141 -0
  377. autocoder/common/v2/agent/tool_caller/test_tool_caller.py +278 -0
  378. autocoder/common/v2/agent/tool_caller/tool_call_plugin_manager.py +331 -0
  379. autocoder/common/v2/agent/tool_caller/tool_caller.py +337 -0
  380. autocoder/common/v2/agent/tool_caller/usage_example.py +193 -0
  381. autocoder/common/v2/code_agentic_editblock_manager.py +4 -4
  382. autocoder/common/v2/code_auto_generate.py +136 -78
  383. autocoder/common/v2/code_auto_generate_diff.py +135 -79
  384. autocoder/common/v2/code_auto_generate_editblock.py +174 -99
  385. autocoder/common/v2/code_auto_generate_strict_diff.py +151 -71
  386. autocoder/common/v2/code_auto_merge.py +1 -1
  387. autocoder/common/v2/code_auto_merge_editblock.py +13 -1
  388. autocoder/common/v2/code_diff_manager.py +3 -3
  389. autocoder/common/v2/code_editblock_manager.py +4 -14
  390. autocoder/common/v2/code_manager.py +1 -1
  391. autocoder/common/v2/code_strict_diff_manager.py +2 -2
  392. autocoder/common/wrap_llm_hint/__init__.py +10 -0
  393. autocoder/common/wrap_llm_hint/test_wrap_llm_hint.py +1067 -0
  394. autocoder/common/wrap_llm_hint/utils.py +432 -0
  395. autocoder/common/wrap_llm_hint/wrap_llm_hint.py +323 -0
  396. autocoder/completer/__init__.py +8 -0
  397. autocoder/completer/command_completer_v2.py +1051 -0
  398. autocoder/default_project/__init__.py +501 -0
  399. autocoder/dispacher/__init__.py +4 -12
  400. autocoder/dispacher/actions/action.py +165 -7
  401. autocoder/dispacher/actions/plugins/action_regex_project.py +2 -2
  402. autocoder/index/entry.py +116 -124
  403. autocoder/{agent → index/filter}/agentic_filter.py +322 -333
  404. autocoder/index/filter/normal_filter.py +5 -11
  405. autocoder/index/filter/quick_filter.py +1 -1
  406. autocoder/index/index.py +36 -9
  407. autocoder/index/tests/__init__.py +1 -0
  408. autocoder/index/tests/run_tests.py +195 -0
  409. autocoder/index/tests/test_entry.py +303 -0
  410. autocoder/index/tests/test_index_manager.py +314 -0
  411. autocoder/index/tests/test_module_integration.py +300 -0
  412. autocoder/index/tests/test_symbols_utils.py +183 -0
  413. autocoder/inner/__init__.py +4 -0
  414. autocoder/inner/agentic.py +932 -0
  415. autocoder/inner/async_command_handler.py +992 -0
  416. autocoder/inner/conversation_command_handlers.py +623 -0
  417. autocoder/inner/merge_command_handler.py +213 -0
  418. autocoder/inner/queue_command_handler.py +684 -0
  419. autocoder/models.py +95 -266
  420. autocoder/plugins/git_helper_plugin.py +31 -29
  421. autocoder/plugins/token_helper_plugin.py +65 -46
  422. autocoder/pyproject/__init__.py +32 -29
  423. autocoder/rag/agentic_rag.py +215 -75
  424. autocoder/rag/cache/simple_cache.py +1 -2
  425. autocoder/rag/loaders/image_loader.py +1 -1
  426. autocoder/rag/long_context_rag.py +42 -26
  427. autocoder/rag/qa_conversation_strategy.py +1 -1
  428. autocoder/rag/terminal/__init__.py +17 -0
  429. autocoder/rag/terminal/args.py +581 -0
  430. autocoder/rag/terminal/bootstrap.py +61 -0
  431. autocoder/rag/terminal/command_handlers.py +653 -0
  432. autocoder/rag/terminal/formatters/__init__.py +20 -0
  433. autocoder/rag/terminal/formatters/base.py +70 -0
  434. autocoder/rag/terminal/formatters/json_format.py +66 -0
  435. autocoder/rag/terminal/formatters/stream_json.py +95 -0
  436. autocoder/rag/terminal/formatters/text.py +28 -0
  437. autocoder/rag/terminal/init.py +120 -0
  438. autocoder/rag/terminal/utils.py +106 -0
  439. autocoder/rag/test_agentic_rag.py +389 -0
  440. autocoder/rag/test_doc_filter.py +3 -3
  441. autocoder/rag/test_long_context_rag.py +1 -1
  442. autocoder/rag/test_token_limiter.py +517 -10
  443. autocoder/rag/token_counter.py +3 -0
  444. autocoder/rag/token_limiter.py +19 -15
  445. autocoder/rag/tools/__init__.py +26 -2
  446. autocoder/rag/tools/bochaai_example.py +343 -0
  447. autocoder/rag/tools/bochaai_sdk.py +541 -0
  448. autocoder/rag/tools/metaso_example.py +268 -0
  449. autocoder/rag/tools/metaso_sdk.py +417 -0
  450. autocoder/rag/tools/recall_tool.py +28 -7
  451. autocoder/rag/tools/run_integration_tests.py +204 -0
  452. autocoder/rag/tools/test_all_providers.py +318 -0
  453. autocoder/rag/tools/test_bochaai_integration.py +482 -0
  454. autocoder/rag/tools/test_final_integration.py +215 -0
  455. autocoder/rag/tools/test_metaso_integration.py +424 -0
  456. autocoder/rag/tools/test_metaso_real.py +171 -0
  457. autocoder/rag/tools/test_web_crawl_tool.py +639 -0
  458. autocoder/rag/tools/test_web_search_tool.py +509 -0
  459. autocoder/rag/tools/todo_read_tool.py +202 -0
  460. autocoder/rag/tools/todo_write_tool.py +412 -0
  461. autocoder/rag/tools/web_crawl_tool.py +634 -0
  462. autocoder/rag/tools/web_search_tool.py +558 -0
  463. autocoder/rag/tools/web_tools_example.py +119 -0
  464. autocoder/rag/types.py +16 -0
  465. autocoder/rag/variable_holder.py +4 -2
  466. autocoder/rags.py +86 -79
  467. autocoder/regexproject/__init__.py +23 -21
  468. autocoder/sdk/__init__.py +46 -190
  469. autocoder/sdk/api.py +370 -0
  470. autocoder/sdk/async_runner/__init__.py +26 -0
  471. autocoder/sdk/async_runner/async_executor.py +650 -0
  472. autocoder/sdk/async_runner/async_handler.py +356 -0
  473. autocoder/sdk/async_runner/markdown_processor.py +595 -0
  474. autocoder/sdk/async_runner/task_metadata.py +284 -0
  475. autocoder/sdk/async_runner/worktree_manager.py +438 -0
  476. autocoder/sdk/cli/__init__.py +2 -5
  477. autocoder/sdk/cli/formatters.py +28 -204
  478. autocoder/sdk/cli/handlers.py +77 -44
  479. autocoder/sdk/cli/main.py +154 -171
  480. autocoder/sdk/cli/options.py +95 -22
  481. autocoder/sdk/constants.py +139 -51
  482. autocoder/sdk/core/auto_coder_core.py +484 -109
  483. autocoder/sdk/core/bridge.py +297 -115
  484. autocoder/sdk/exceptions.py +18 -12
  485. autocoder/sdk/formatters/__init__.py +19 -0
  486. autocoder/sdk/formatters/input.py +64 -0
  487. autocoder/sdk/formatters/output.py +247 -0
  488. autocoder/sdk/formatters/stream.py +54 -0
  489. autocoder/sdk/models/__init__.py +6 -5
  490. autocoder/sdk/models/options.py +55 -18
  491. autocoder/sdk/utils/formatters.py +27 -195
  492. autocoder/suffixproject/__init__.py +28 -25
  493. autocoder/terminal/__init__.py +14 -0
  494. autocoder/terminal/app.py +454 -0
  495. autocoder/terminal/args.py +32 -0
  496. autocoder/terminal/bootstrap.py +178 -0
  497. autocoder/terminal/command_processor.py +521 -0
  498. autocoder/terminal/command_registry.py +57 -0
  499. autocoder/terminal/help.py +97 -0
  500. autocoder/terminal/tasks/__init__.py +5 -0
  501. autocoder/terminal/tasks/background.py +77 -0
  502. autocoder/terminal/tasks/task_event.py +70 -0
  503. autocoder/terminal/ui/__init__.py +13 -0
  504. autocoder/terminal/ui/completer.py +268 -0
  505. autocoder/terminal/ui/keybindings.py +75 -0
  506. autocoder/terminal/ui/session.py +41 -0
  507. autocoder/terminal/ui/toolbar.py +64 -0
  508. autocoder/terminal/utils/__init__.py +13 -0
  509. autocoder/terminal/utils/errors.py +18 -0
  510. autocoder/terminal/utils/paths.py +19 -0
  511. autocoder/terminal/utils/shell.py +43 -0
  512. autocoder/terminal_v3/__init__.py +10 -0
  513. autocoder/terminal_v3/app.py +201 -0
  514. autocoder/terminal_v3/handlers/__init__.py +5 -0
  515. autocoder/terminal_v3/handlers/command_handler.py +131 -0
  516. autocoder/terminal_v3/models/__init__.py +6 -0
  517. autocoder/terminal_v3/models/conversation_buffer.py +214 -0
  518. autocoder/terminal_v3/models/message.py +50 -0
  519. autocoder/terminal_v3/models/tool_display.py +247 -0
  520. autocoder/terminal_v3/ui/__init__.py +7 -0
  521. autocoder/terminal_v3/ui/keybindings.py +56 -0
  522. autocoder/terminal_v3/ui/layout.py +141 -0
  523. autocoder/terminal_v3/ui/styles.py +43 -0
  524. autocoder/tsproject/__init__.py +23 -23
  525. autocoder/utils/auto_coder_utils/chat_stream_out.py +1 -1
  526. autocoder/utils/llms.py +88 -80
  527. autocoder/utils/math_utils.py +101 -0
  528. autocoder/utils/model_provider_selector.py +16 -4
  529. autocoder/utils/operate_config_api.py +33 -5
  530. autocoder/utils/thread_utils.py +2 -2
  531. autocoder/version.py +4 -2
  532. autocoder/workflow_agents/__init__.py +84 -0
  533. autocoder/workflow_agents/agent.py +143 -0
  534. autocoder/workflow_agents/exceptions.py +573 -0
  535. autocoder/workflow_agents/executor.py +489 -0
  536. autocoder/workflow_agents/loader.py +737 -0
  537. autocoder/workflow_agents/runner.py +267 -0
  538. autocoder/workflow_agents/types.py +172 -0
  539. autocoder/workflow_agents/utils.py +434 -0
  540. autocoder/workflow_agents/workflow_manager.py +211 -0
  541. auto_coder-1.0.0.dist-info/METADATA +0 -396
  542. auto_coder-1.0.0.dist-info/RECORD +0 -442
  543. auto_coder-1.0.0.dist-info/licenses/LICENSE +0 -201
  544. autocoder/auto_coder_server.py +0 -672
  545. autocoder/benchmark.py +0 -138
  546. autocoder/common/ac_style_command_parser/example.py +0 -7
  547. autocoder/common/cleaner.py +0 -31
  548. autocoder/common/command_completer_v2.py +0 -615
  549. autocoder/common/context_pruner.py +0 -477
  550. autocoder/common/conversation_pruner.py +0 -132
  551. autocoder/common/directory_cache/__init__.py +0 -1
  552. autocoder/common/directory_cache/cache.py +0 -192
  553. autocoder/common/directory_cache/test_cache.py +0 -190
  554. autocoder/common/file_checkpoint/examples.py +0 -217
  555. autocoder/common/llm_friendly_package_example.py +0 -138
  556. autocoder/common/llm_friendly_package_test.py +0 -63
  557. autocoder/common/pull_requests/test_module.py +0 -1
  558. autocoder/common/rulefiles/autocoderrules_utils.py +0 -484
  559. autocoder/common/text.py +0 -30
  560. autocoder/common/v2/agent/agentic_edit_tools/list_package_info_tool_resolver.py +0 -42
  561. autocoder/common/v2/agent/agentic_edit_tools/test_execute_command_tool_resolver.py +0 -70
  562. autocoder/common/v2/agent/agentic_edit_tools/test_search_files_tool_resolver.py +0 -163
  563. autocoder/common/v2/agent/agentic_tool_display.py +0 -183
  564. autocoder/plugins/dynamic_completion_example.py +0 -148
  565. autocoder/plugins/sample_plugin.py +0 -160
  566. autocoder/sdk/cli/__main__.py +0 -26
  567. autocoder/sdk/cli/completion_wrapper.py +0 -38
  568. autocoder/sdk/cli/install_completion.py +0 -301
  569. autocoder/sdk/models/messages.py +0 -209
  570. autocoder/sdk/session/__init__.py +0 -32
  571. autocoder/sdk/session/session.py +0 -106
  572. autocoder/sdk/session/session_manager.py +0 -56
  573. {auto_coder-1.0.0.dist-info → auto_coder-2.0.0.dist-info}/top_level.txt +0 -0
  574. /autocoder/{sdk/example.py → common/agent_query_queue/__init__.py} +0 -0
@@ -0,0 +1,434 @@
1
+ """
2
+ Workflow Agents 工具函数
3
+
4
+ 提供模板渲染、条件评估、JSONPath 处理等辅助功能。
5
+ """
6
+
7
+ import re
8
+ import json
9
+ from typing import Any, Dict, Optional
10
+ from loguru import logger
11
+
12
+ from autocoder.workflow_agents.types import (
13
+ WhenConfig,
14
+ RegexCondition,
15
+ JsonPathCondition,
16
+ OutputConfig,
17
+ )
18
+ from autocoder.workflow_agents.exceptions import (
19
+ WorkflowTemplateError,
20
+ WorkflowConditionError,
21
+ WorkflowOutputExtractionError,
22
+ )
23
+
24
+ # 常量定义
25
+ TEMPLATE_PREFIX = "${"
26
+ TEMPLATE_SUFFIX = "}"
27
+ ATTEMPT_RESULT_VAR = "attempt_result"
28
+ FORMAT_JSON = "json"
29
+ FORMAT_TEXT = "text"
30
+
31
+
32
+ def render_template(template: Any, context: Dict[str, Any]) -> Any:
33
+ """
34
+ 渲染模板字符串
35
+
36
+ 支持的模板语法:
37
+ - ${vars.key} - 访问全局变量
38
+ - ${steps.stepId.outputs.key} - 访问步骤输出
39
+ - ${attempt_result} - 访问上一次的 attempt 结果
40
+ - \\$ - 转义,输出字面的 $
41
+
42
+ 支持在字符串中嵌入多个变量,例如:
43
+ "基于文件 ${steps.step1.outputs.files} 执行 ${vars.action}"
44
+
45
+ Args:
46
+ template: 模板(字符串或其他类型)
47
+ context: 上下文数据,包含 vars、steps 等
48
+
49
+ Returns:
50
+ 渲染后的值
51
+ """
52
+ if not isinstance(template, str):
53
+ return template
54
+
55
+ # 如果没有任何模板标记,直接返回
56
+ if "${" not in template and "\\$" not in template:
57
+ return template
58
+
59
+ # 正则表达式:匹配非转义的 ${...}
60
+ # (?<!\\) - 负向后查找,确保前面不是反斜杠
61
+ # \$\{([^}]+)\} - 匹配 ${...}
62
+ pattern = r"(?<!\\)\$\{([^}]+)\}"
63
+
64
+ def replace_var(match):
65
+ expr = match.group(1).strip()
66
+ try:
67
+ value = _resolve_expression(expr, context)
68
+ # 如果值是 None,返回空字符串
69
+ return str(value) if value is not None else ""
70
+ except (KeyError, IndexError, TypeError) as e:
71
+ # 提供更友好的错误信息
72
+ context_keys = _get_context_keys(context)
73
+ logger.warning(f"模板表达式无法解析: ${{{expr}}}, 可用键: {context_keys}")
74
+ # 抛出友好的异常
75
+ raise WorkflowTemplateError(
76
+ template=template, expression=expr, context_keys=context_keys
77
+ ) from e
78
+
79
+ # 替换所有变量
80
+ result = re.sub(pattern, replace_var, template)
81
+
82
+ # 处理转义:将 \$ 替换为 $
83
+ result = result.replace(r"\$", "$")
84
+
85
+ return result
86
+
87
+
88
+ def _resolve_expression(expr: str, context: Dict[str, Any]) -> Any:
89
+ """
90
+ 解析模板表达式
91
+
92
+ Args:
93
+ expr: 表达式内容(去除 ${ } 后的部分)
94
+ context: 上下文数据
95
+
96
+ Returns:
97
+ 解析后的值
98
+
99
+ Raises:
100
+ KeyError, IndexError, TypeError: 解析失败时抛出
101
+ """
102
+ parts = expr.split(".")
103
+
104
+ # ${vars.key}
105
+ if parts[0] == "vars" and len(parts) >= 2:
106
+ vars_dict = context.get("vars", {})
107
+ if parts[1] not in vars_dict:
108
+ raise KeyError(f"Variable not found: vars.{parts[1]}")
109
+ return vars_dict[parts[1]]
110
+
111
+ # ${steps.stepId.outputs.key}
112
+ if parts[0] == "steps" and len(parts) >= 4 and parts[2] == "outputs":
113
+ step_id = parts[1]
114
+ key = parts[3]
115
+ steps_dict = context.get("steps", {})
116
+ if step_id not in steps_dict:
117
+ raise KeyError(f"Step not found: {step_id}")
118
+ outputs_dict = steps_dict[step_id].get("outputs", {})
119
+ if key not in outputs_dict:
120
+ raise KeyError(f"Output not found: {step_id}.outputs.{key}")
121
+ return outputs_dict[key]
122
+
123
+ # ${attempt_result}
124
+ if expr == ATTEMPT_RESULT_VAR:
125
+ # attempt_result 可能为 None(初始状态),这是合法的
126
+ return context.get("_last_attempt_result")
127
+
128
+ # 不支持的表达式
129
+ raise KeyError(f"不支持的表达式: {expr}")
130
+
131
+
132
+ def evaluate_condition(
133
+ when_config: Optional[WhenConfig],
134
+ attempt_result: Optional[str],
135
+ context: Dict[str, Any],
136
+ ) -> bool:
137
+ """
138
+ 评估条件是否满足
139
+
140
+ Args:
141
+ when_config: 条件配置
142
+ attempt_result: AttemptCompletion 结果字符串
143
+ context: 上下文数据
144
+
145
+ Returns:
146
+ 条件是否满足
147
+ """
148
+ if when_config is None:
149
+ return True
150
+
151
+ # 正则条件
152
+ if when_config.regex is not None:
153
+ return evaluate_regex_condition(when_config.regex, attempt_result, context)
154
+
155
+ # JSONPath 条件
156
+ if when_config.jsonpath is not None:
157
+ return evaluate_jsonpath_condition(
158
+ when_config.jsonpath, attempt_result, context
159
+ )
160
+
161
+ return True
162
+
163
+
164
+ def _get_input_string(
165
+ input_template: str, context: Dict[str, Any], fallback: Optional[str]
166
+ ) -> str:
167
+ """
168
+ 获取输入字符串(公共逻辑)
169
+
170
+ Args:
171
+ input_template: 输入模板
172
+ context: 上下文数据
173
+ fallback: 回退值(通常是 attempt_result)
174
+
175
+ Returns:
176
+ 解析后的输入字符串
177
+ """
178
+ if input_template:
179
+ return str(render_template(input_template, context))
180
+ return fallback or ""
181
+
182
+
183
+ def evaluate_regex_condition(
184
+ regex_config: RegexCondition, attempt_result: Optional[str], context: Dict[str, Any]
185
+ ) -> bool:
186
+ """
187
+ 评估正则条件
188
+
189
+ Args:
190
+ regex_config: 正则条件配置
191
+ attempt_result: AttemptCompletion 结果字符串
192
+ context: 上下文数据
193
+
194
+ Returns:
195
+ 条件是否满足
196
+ """
197
+ input_str = _get_input_string(regex_config.input, context, attempt_result)
198
+ pattern = regex_config.pattern
199
+
200
+ flags = 0
201
+ if regex_config.flags and regex_config.flags.lower() == "i":
202
+ flags |= re.IGNORECASE
203
+
204
+ match = re.search(pattern, input_str, flags)
205
+ return match is not None
206
+
207
+
208
+ def evaluate_jsonpath_condition(
209
+ jsonpath_config: JsonPathCondition,
210
+ attempt_result: Optional[str],
211
+ context: Dict[str, Any],
212
+ ) -> bool:
213
+ """
214
+ 评估 JSONPath 条件
215
+
216
+ Args:
217
+ jsonpath_config: JSONPath 条件配置
218
+ attempt_result: AttemptCompletion 结果字符串
219
+ context: 上下文数据
220
+
221
+ Returns:
222
+ 条件是否满足
223
+ """
224
+ input_str = _get_input_string(jsonpath_config.input, context, attempt_result)
225
+
226
+ try:
227
+ data = json.loads(input_str)
228
+ except Exception:
229
+ return False
230
+
231
+ path = jsonpath_config.path
232
+ value = extract_jsonpath_value(data, path)
233
+
234
+ # exists 检查
235
+ if jsonpath_config.exists is not None:
236
+ return (value is not None) == jsonpath_config.exists
237
+
238
+ # equals 检查
239
+ if jsonpath_config.equals is not None:
240
+ return value == jsonpath_config.equals
241
+
242
+ # contains 检查
243
+ if jsonpath_config.contains is not None and isinstance(value, str):
244
+ return jsonpath_config.contains in value
245
+
246
+ # 默认:检查值是否存在且非空
247
+ return bool(value)
248
+
249
+
250
+ def extract_jsonpath_value(data: Any, path: str) -> Any:
251
+ """
252
+ 从 JSON 数据中提取 JSONPath 路径的值
253
+
254
+ 简化实现,仅支持顶层访问:$.key
255
+
256
+ Args:
257
+ data: JSON 数据
258
+ path: JSONPath 路径
259
+
260
+ Returns:
261
+ 提取的值,如果路径不存在则返回 None
262
+ """
263
+ if not isinstance(data, dict):
264
+ return None
265
+
266
+ if path.startswith("$."):
267
+ key = path[2:]
268
+ return data.get(key)
269
+
270
+ return None
271
+
272
+
273
+ def extract_outputs(
274
+ outputs_map: Dict[str, Any],
275
+ attempt_result: str,
276
+ attempt_format: str,
277
+ default_jsonpaths: Dict[str, str],
278
+ context: Dict[str, Any],
279
+ ) -> Dict[str, Any]:
280
+ """
281
+ 从 AttemptCompletion 结果中提取输出
282
+
283
+ Args:
284
+ outputs_map: 输出映射配置
285
+ attempt_result: AttemptCompletion 结果字符串
286
+ attempt_format: 格式(json | text)
287
+ default_jsonpaths: 默认 JSONPath 映射
288
+ context: 上下文数据
289
+
290
+ Returns:
291
+ 提取的输出字典
292
+ """
293
+ if not outputs_map:
294
+ return {"attempt_raw": attempt_result}
295
+
296
+ # 如果格式是 JSON,尝试解析
297
+ parsed_json = _try_parse_json(attempt_result, attempt_format)
298
+
299
+ # 提取每个输出
300
+ extracted: Dict[str, Any] = {}
301
+ for key, spec in outputs_map.items():
302
+ value = _extract_single_output(
303
+ key, spec, attempt_result, parsed_json, default_jsonpaths
304
+ )
305
+ extracted[key] = value
306
+
307
+ # 确保总是有 attempt_raw
308
+ extracted.setdefault("attempt_raw", attempt_result)
309
+ return extracted
310
+
311
+
312
+ def _try_parse_json(
313
+ attempt_result: str, attempt_format: str
314
+ ) -> Optional[Dict[str, Any]]:
315
+ """
316
+ 尝试将 attempt_result 解析为 JSON
317
+
318
+ Args:
319
+ attempt_result: AttemptCompletion 结果字符串
320
+ attempt_format: 格式(json | text)
321
+
322
+ Returns:
323
+ 解析后的 JSON 字典,如果失败或格式不是 json 则返回 None
324
+ """
325
+ if attempt_format != FORMAT_JSON:
326
+ return None
327
+
328
+ try:
329
+ return json.loads(attempt_result)
330
+ except Exception:
331
+ return None
332
+
333
+
334
+ def _extract_single_output(
335
+ key: str,
336
+ spec: Any,
337
+ attempt_result: str,
338
+ parsed_json: Optional[Dict[str, Any]],
339
+ default_jsonpaths: Dict[str, str],
340
+ ) -> Any:
341
+ """
342
+ 提取单个输出值
343
+
344
+ Args:
345
+ key: 输出键名
346
+ spec: 输出配置(可能是字符串或 OutputConfig)
347
+ attempt_result: 原始结果字符串
348
+ parsed_json: 解析后的 JSON(如果有)
349
+ default_jsonpaths: 默认 JSONPath 映射
350
+
351
+ Returns:
352
+ 提取的值
353
+ """
354
+ # 直接透传 attempt_result(兼容旧代码)
355
+ template_value = f"{TEMPLATE_PREFIX}{ATTEMPT_RESULT_VAR}{TEMPLATE_SUFFIX}"
356
+ if isinstance(spec, str) and spec == template_value:
357
+ return attempt_result
358
+
359
+ # 不是 OutputConfig 对象,返回 None
360
+ if not isinstance(spec, OutputConfig):
361
+ return None
362
+
363
+ # 模板字符串提取(新增支持)
364
+ if spec.template is not None:
365
+ # 如果是 ${attempt_result},直接返回
366
+ if spec.template == template_value:
367
+ return attempt_result
368
+ # 否则作为普通值返回(可能是其他模板)
369
+ return spec.template
370
+
371
+ # JSONPath 提取
372
+ if spec.jsonpath is not None and parsed_json is not None:
373
+ path = spec.jsonpath if spec.jsonpath else default_jsonpaths.get(key, "")
374
+ return extract_jsonpath_value(parsed_json, path)
375
+
376
+ # 正则提取
377
+ if spec.regex is not None:
378
+ return _extract_by_regex(spec.regex, spec.regex_group, attempt_result)
379
+
380
+ return None
381
+
382
+
383
+ def _extract_by_regex(pattern: str, group: Optional[int], text: str) -> Optional[str]:
384
+ """
385
+ 使用正则表达式提取文本
386
+
387
+ Args:
388
+ pattern: 正则表达式模式
389
+ group: 捕获组索引(None 表示整个匹配)
390
+ text: 待提取的文本
391
+
392
+ Returns:
393
+ 提取的文本,如果未匹配则返回 None
394
+ """
395
+ match = re.search(pattern, text)
396
+ if not match:
397
+ return None
398
+
399
+ if group is None:
400
+ return match.group(0)
401
+ return match.group(group)
402
+
403
+
404
+ def _get_context_keys(context: Dict[str, Any]) -> list:
405
+ """
406
+ 获取上下文中所有可用的键(用于错误提示)
407
+
408
+ Args:
409
+ context: 上下文数据
410
+
411
+ Returns:
412
+ 可用键的列表
413
+ """
414
+ keys = []
415
+
416
+ # vars.*
417
+ if "vars" in context and isinstance(context["vars"], dict):
418
+ for var_key in context["vars"].keys():
419
+ keys.append(f"vars.{var_key}")
420
+
421
+ # steps.*.outputs.*
422
+ if "steps" in context and isinstance(context["steps"], dict):
423
+ for step_id, step_data in context["steps"].items():
424
+ if isinstance(step_data, dict) and "outputs" in step_data:
425
+ outputs = step_data["outputs"]
426
+ if isinstance(outputs, dict):
427
+ for output_key in outputs.keys():
428
+ keys.append(f"steps.{step_id}.outputs.{output_key}")
429
+
430
+ # attempt_result
431
+ if "_last_attempt_result" in context:
432
+ keys.append("attempt_result")
433
+
434
+ return keys
@@ -0,0 +1,211 @@
1
+ """
2
+ Workflow Manager - 管理 workflow 文件的查找和加载
3
+
4
+ 提供优先级搜索路径支持,类似 AgentManager。
5
+ """
6
+
7
+ from pathlib import Path
8
+ from typing import List, Optional, Dict, Any
9
+ from loguru import logger
10
+
11
+ from autocoder.common.priority_directory_finder import (
12
+ PriorityDirectoryFinder,
13
+ FinderConfig,
14
+ SearchStrategy,
15
+ ValidationMode,
16
+ create_file_filter,
17
+ )
18
+
19
+ # 常量定义
20
+ WORKFLOW_DIR_NAME = ".autocoderworkflow"
21
+ WORKFLOW_EXTENSIONS = [".yaml", ".yml"]
22
+
23
+
24
+ class WorkflowManager:
25
+ """
26
+ Workflow 文件管理器
27
+
28
+ 支持从多个目录按优先级查找 workflow YAML 文件:
29
+ 1. .autocoderworkflow (项目级,最高优先级)
30
+ 2. .auto-coder/.autocoderworkflow (项目级)
31
+ 3. ~/.auto-coder/.autocoderworkflow (全局级)
32
+ """
33
+
34
+ def __init__(self, project_root: str):
35
+ """
36
+ 初始化 WorkflowManager
37
+
38
+ Args:
39
+ project_root: 项目根目录
40
+ """
41
+ self.project_root = Path(project_root)
42
+ self.workflow_directories: List[str] = []
43
+ self._discover_directories()
44
+
45
+ def _get_workflow_search_paths(self) -> List[Path]:
46
+ """
47
+ 获取 workflow 搜索路径列表(按优先级排序)
48
+
49
+ Returns:
50
+ 搜索路径列表
51
+ """
52
+ return [
53
+ self.project_root / WORKFLOW_DIR_NAME, # 项目级(最高)
54
+ self.project_root / ".auto-coder" / WORKFLOW_DIR_NAME, # 项目级
55
+ Path.home() / ".auto-coder" / WORKFLOW_DIR_NAME, # 全局级
56
+ ]
57
+
58
+ def _discover_directories(self) -> None:
59
+ """使用优先级目录查找器发现 workflow 目录"""
60
+ try:
61
+ # 创建文件过滤器
62
+ yaml_filter = create_file_filter(
63
+ extensions=WORKFLOW_EXTENSIONS, recursive=False
64
+ )
65
+
66
+ # 创建查找器配置,使用 MERGE_ALL 策略
67
+ config = FinderConfig(strategy=SearchStrategy.MERGE_ALL)
68
+
69
+ # 按优先级添加目录
70
+ config.add_directory(
71
+ path=str(self.project_root / WORKFLOW_DIR_NAME),
72
+ priority=1,
73
+ validation_mode=ValidationMode.HAS_SPECIFIC_FILES,
74
+ file_filter=yaml_filter,
75
+ description="项目级 workflow 目录",
76
+ )
77
+ config.add_directory(
78
+ path=str(self.project_root / ".auto-coder" / WORKFLOW_DIR_NAME),
79
+ priority=2,
80
+ validation_mode=ValidationMode.HAS_SPECIFIC_FILES,
81
+ file_filter=yaml_filter,
82
+ description="项目 .auto-coder workflow 目录",
83
+ )
84
+ config.add_directory(
85
+ path=f"~/.auto-coder/{WORKFLOW_DIR_NAME}",
86
+ priority=3,
87
+ validation_mode=ValidationMode.HAS_SPECIFIC_FILES,
88
+ file_filter=yaml_filter,
89
+ description="全局 workflow 目录",
90
+ )
91
+
92
+ # 执行查找
93
+ finder = PriorityDirectoryFinder(config)
94
+ result = finder.find_directories()
95
+
96
+ if result.success and result.selected_directories:
97
+ logger.debug(
98
+ f"使用优先级查找器找到 {len(result.selected_directories)} 个 workflow 目录"
99
+ )
100
+ self.workflow_directories = result.selected_directories
101
+ else:
102
+ logger.debug("优先级查找器未找到包含 workflow 文件的目录")
103
+ self.workflow_directories = []
104
+
105
+ except Exception as e:
106
+ logger.warning(f"使用优先级查找器发现 workflow 目录时出错: {e}")
107
+ # 回退到传统方法
108
+ self._discover_directories_fallback()
109
+
110
+ def _discover_directories_fallback(self) -> None:
111
+ """回退到传统的目录发现方法"""
112
+ logger.debug("回退到传统的 workflow 目录查找方法")
113
+ search_paths = self._get_workflow_search_paths()
114
+
115
+ self.workflow_directories = []
116
+ for path in search_paths:
117
+ if path.exists() and path.is_dir():
118
+ # 检查是否有 .yaml 或 .yml 文件
119
+ yaml_files = list(path.glob("*.yaml")) + list(path.glob("*.yml"))
120
+ if yaml_files:
121
+ self.workflow_directories.append(str(path))
122
+
123
+ def find_workflow(self, workflow_name: str) -> Optional[str]:
124
+ """
125
+ 按优先级查找 workflow 文件
126
+
127
+ 支持的文件名格式:
128
+ - workflow_name.yaml
129
+ - workflow_name.yml
130
+
131
+ Args:
132
+ workflow_name: workflow 名称(不含扩展名)
133
+
134
+ Returns:
135
+ 找到的 workflow 文件绝对路径,如果未找到则返回 None
136
+ """
137
+ # 按优先级顺序查找
138
+ for directory in self.workflow_directories:
139
+ found_path = self._find_workflow_in_directory(
140
+ Path(directory), workflow_name
141
+ )
142
+ if found_path:
143
+ logger.info(f"找到 workflow: {found_path}")
144
+ return found_path
145
+
146
+ logger.warning(f"未找到 workflow: {workflow_name}")
147
+ return None
148
+
149
+ def _find_workflow_in_directory(
150
+ self, dir_path: Path, workflow_name: str
151
+ ) -> Optional[str]:
152
+ """
153
+ 在指定目录中查找 workflow 文件
154
+
155
+ Args:
156
+ dir_path: 目录路径
157
+ workflow_name: workflow 名称
158
+
159
+ Returns:
160
+ 找到的文件路径,否则返回 None
161
+ """
162
+ for ext in WORKFLOW_EXTENSIONS:
163
+ workflow_path = dir_path / f"{workflow_name}{ext}"
164
+ if workflow_path.exists():
165
+ return str(workflow_path)
166
+ return None
167
+
168
+ def list_workflows(self) -> Dict[str, str]:
169
+ """
170
+ 列出所有可用的 workflow
171
+
172
+ Returns:
173
+ 字典,key 为 workflow 名称(不含扩展名),value 为文件路径
174
+ """
175
+ workflows: Dict[str, str] = {}
176
+
177
+ # 从低优先级到高优先级遍历,高优先级会覆盖低优先级
178
+ for directory in reversed(self.workflow_directories):
179
+ dir_path = Path(directory)
180
+
181
+ # 查找所有 .yaml 和 .yml 文件
182
+ for yaml_file in list(dir_path.glob("*.yaml")) + list(
183
+ dir_path.glob("*.yml")
184
+ ):
185
+ workflow_name = yaml_file.stem
186
+ workflows[workflow_name] = str(yaml_file)
187
+
188
+ return workflows
189
+
190
+ def get_workflow_directories(self) -> List[str]:
191
+ """
192
+ 获取所有 workflow 目录路径
193
+
194
+ Returns:
195
+ workflow 目录路径列表,按优先级排序
196
+ """
197
+ return self.workflow_directories.copy()
198
+
199
+ def to_dict(self) -> Dict[str, Any]:
200
+ """
201
+ 转换为字典表示
202
+
203
+ Returns:
204
+ 包含搜索路径和可用 workflow 的字典
205
+ """
206
+ return {
207
+ "project_root": str(self.project_root),
208
+ "search_paths": [str(p) for p in self._get_workflow_search_paths()],
209
+ "workflow_directories": self.workflow_directories,
210
+ "workflows": self.list_workflows(),
211
+ }