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,600 @@
1
+
2
+ """
3
+ WebSearchToolResolver Module
4
+
5
+ This module implements the WebSearchToolResolver class for providing
6
+ web search functionality based on Firecrawl, Metaso, or BochaAI within
7
+ the AgenticEdit framework. Supports concurrent search when multiple API
8
+ keys are configured, using thread pools for concurrent processing.
9
+ """
10
+
11
+ import os
12
+ import traceback
13
+ import json
14
+ from typing import Dict, Any, List, Optional
15
+ from concurrent.futures import ThreadPoolExecutor, as_completed
16
+ from threading import Lock
17
+
18
+ from loguru import logger
19
+
20
+ from autocoder.common.v2.agent.agentic_edit_tools.base_tool_resolver import BaseToolResolver
21
+ from autocoder.common.v2.agent.agentic_edit_types import WebSearchTool, ToolResult
22
+ from autocoder.common import AutoCoderArgs
23
+ import typing
24
+
25
+ if typing.TYPE_CHECKING:
26
+ from autocoder.common.v2.agent.agentic_edit import AgenticEdit
27
+
28
+
29
+ class WebSearchToolResolver(BaseToolResolver):
30
+ """Web search tool resolver that implements concurrent search logic"""
31
+
32
+ def __init__(self, agent: Optional['AgenticEdit'], tool: WebSearchTool, args: AutoCoderArgs):
33
+ super().__init__(agent, tool, args)
34
+ self.tool: WebSearchTool = tool
35
+ self._results_lock = Lock()
36
+ self._all_results = []
37
+
38
+ def _get_available_providers(self) -> List[Dict[str, Any]]:
39
+ """Get all available provider configurations"""
40
+ providers = []
41
+
42
+ # Check BochaAI keys
43
+ bochaai_keys = []
44
+ if hasattr(self.args, 'bochaai_api_key') and self.args.bochaai_api_key:
45
+ if ',' in self.args.bochaai_api_key:
46
+ bochaai_keys = [key.strip() for key in self.args.bochaai_api_key.split(',') if key.strip()]
47
+ else:
48
+ bochaai_keys = [self.args.bochaai_api_key]
49
+ elif os.getenv('BOCHAAI_API_KEY'):
50
+ env_keys = os.getenv('BOCHAAI_API_KEY')
51
+ if ',' in env_keys:
52
+ bochaai_keys = [key.strip() for key in env_keys.split(',') if key.strip()]
53
+ else:
54
+ bochaai_keys = [env_keys]
55
+
56
+ for key in bochaai_keys:
57
+ providers.append({
58
+ 'type': 'bochaai',
59
+ 'api_key': key,
60
+ 'priority': 1
61
+ })
62
+
63
+ # Check Metaso keys
64
+ metaso_keys = []
65
+ if hasattr(self.args, 'metaso_api_key') and self.args.metaso_api_key:
66
+ if ',' in self.args.metaso_api_key:
67
+ metaso_keys = [key.strip() for key in self.args.metaso_api_key.split(',') if key.strip()]
68
+ else:
69
+ metaso_keys = [self.args.metaso_api_key]
70
+ elif os.getenv('METASO_API_KEY'):
71
+ env_keys = os.getenv('METASO_API_KEY')
72
+ if ',' in env_keys:
73
+ metaso_keys = [key.strip() for key in env_keys.split(',') if key.strip()]
74
+ else:
75
+ metaso_keys = [env_keys]
76
+
77
+ for key in metaso_keys:
78
+ providers.append({
79
+ 'type': 'metaso',
80
+ 'api_key': key,
81
+ 'priority': 2
82
+ })
83
+
84
+ # Check Firecrawl keys
85
+ firecrawl_keys = []
86
+ if hasattr(self.args, 'firecrawl_api_key') and self.args.firecrawl_api_key:
87
+ if ',' in self.args.firecrawl_api_key:
88
+ firecrawl_keys = [key.strip() for key in self.args.firecrawl_api_key.split(',') if key.strip()]
89
+ else:
90
+ firecrawl_keys = [self.args.firecrawl_api_key]
91
+ elif os.getenv('FIRECRAWL_API_KEY'):
92
+ env_keys = os.getenv('FIRECRAWL_API_KEY')
93
+ if ',' in env_keys:
94
+ firecrawl_keys = [key.strip() for key in env_keys.split(',') if key.strip()]
95
+ else:
96
+ firecrawl_keys = [env_keys]
97
+
98
+ for key in firecrawl_keys:
99
+ providers.append({
100
+ 'type': 'firecrawl',
101
+ 'api_key': key,
102
+ 'priority': 3
103
+ })
104
+
105
+ # Sort by priority
106
+ providers.sort(key=lambda x: x['priority'])
107
+ return providers
108
+
109
+ def _search_with_bochaai(self, api_key: str) -> ToolResult:
110
+ """Search using BochaAI"""
111
+ try:
112
+ # Dynamic import to avoid dependency issues
113
+ try:
114
+ from autocoder.rag.tools.bochaai_sdk import BochaAIClient
115
+ except ImportError:
116
+ return ToolResult(
117
+ success=False,
118
+ message="BochaAI SDK not installed, please check dependencies",
119
+ content=[]
120
+ )
121
+
122
+ # Initialize BochaAI client
123
+ client = BochaAIClient(api_key=api_key)
124
+
125
+ # Prepare search parameters
126
+ freshness = "noLimit" # Default no time limit
127
+ if self.tool.tbs:
128
+ # Map time filter parameters
129
+ tbs_mapping = {
130
+ "d": "oneDay",
131
+ "w": "oneWeek",
132
+ "m": "oneMonth",
133
+ "y": "oneYear"
134
+ }
135
+ freshness = tbs_mapping.get(self.tool.tbs, "noLimit")
136
+
137
+ # Parse scrape_options to get additional parameters
138
+ include_summary = False
139
+ include_sites = None
140
+ exclude_sites = None
141
+ if self.tool.scrape_options:
142
+ try:
143
+ scrape_opts = json.loads(self.tool.scrape_options)
144
+ include_summary = scrape_opts.get('include_summary', False) or scrape_opts.get('summary', False)
145
+ include_sites = scrape_opts.get('include_sites')
146
+ exclude_sites = scrape_opts.get('exclude_sites')
147
+ except json.JSONDecodeError:
148
+ pass
149
+
150
+ # Execute search
151
+ logger.info(f"Performing web search using BochaAI, query: {self.tool.query}")
152
+ result = client.search(
153
+ query=self.tool.query,
154
+ count=self.tool.limit,
155
+ freshness=freshness,
156
+ summary=include_summary,
157
+ include=include_sites,
158
+ exclude=exclude_sites
159
+ )
160
+
161
+ if not result.success:
162
+ return ToolResult(
163
+ success=False,
164
+ message=f"BochaAI search failed: {result.error}",
165
+ content=[]
166
+ )
167
+
168
+ # Format search results
169
+ search_results = []
170
+
171
+ # Process web results
172
+ for webpage in result.webpages:
173
+ result_item = {
174
+ "type": "web",
175
+ "title": webpage.name,
176
+ "url": webpage.url,
177
+ "description": webpage.snippet,
178
+ "provider": "bochaai",
179
+ "api_key_suffix": api_key[-4:] if len(api_key) > 4 else "****"
180
+ }
181
+
182
+ if webpage.summary:
183
+ result_item["summary"] = webpage.summary
184
+ if webpage.date_published:
185
+ result_item["date"] = webpage.date_published
186
+ if webpage.site_name:
187
+ result_item["site_name"] = webpage.site_name
188
+ if webpage.site_icon:
189
+ result_item["site_icon"] = webpage.site_icon
190
+
191
+ search_results.append(result_item)
192
+
193
+ # Process image results (if needed)
194
+ if self.tool.sources and "images" in self.tool.sources:
195
+ for image in result.images:
196
+ image_item = {
197
+ "type": "image",
198
+ "url": image.content_url,
199
+ "thumbnail_url": image.thumbnail_url,
200
+ "host_page_url": image.host_page_url,
201
+ "width": image.width,
202
+ "height": image.height,
203
+ "provider": "bochaai",
204
+ "api_key_suffix": api_key[-4:] if len(api_key) > 4 else "****"
205
+ }
206
+ if image.name:
207
+ image_item["title"] = image.name
208
+ search_results.append(image_item)
209
+
210
+ return ToolResult(
211
+ success=True,
212
+ message=f"Successfully found {len(search_results)} results (using BochaAI)",
213
+ content=search_results
214
+ )
215
+
216
+ except Exception as e:
217
+ logger.error(f"BochaAI search failed: {str(e)}")
218
+ return ToolResult(
219
+ success=False,
220
+ message=f"BochaAI search failed: {str(e)}",
221
+ content=[]
222
+ )
223
+
224
+ def _search_with_metaso(self, api_key: str) -> ToolResult:
225
+ """Search using Metaso"""
226
+ try:
227
+ # Dynamic import to avoid dependency issues
228
+ try:
229
+ from autocoder.rag.tools.metaso_sdk import MetasoClient
230
+ except ImportError:
231
+ return ToolResult(
232
+ success=False,
233
+ message="Metaso SDK not installed, please check dependencies",
234
+ content=[]
235
+ )
236
+
237
+ # Initialize Metaso client
238
+ client = MetasoClient(api_key=api_key)
239
+
240
+ # Prepare search parameters
241
+ scope = "webpage" # Default search web pages
242
+ if self.tool.sources:
243
+ # Map sources to Metaso's scope
244
+ sources_list = [s.strip().lower() for s in self.tool.sources.split(',')]
245
+ if "news" in sources_list:
246
+ scope = "news"
247
+ # Metaso does not support images search yet, keep default webpage
248
+
249
+ # Parse scrape_options to get additional parameters
250
+ include_summary = False
251
+ include_raw_content = False
252
+ if self.tool.scrape_options:
253
+ try:
254
+ scrape_opts = json.loads(self.tool.scrape_options)
255
+ include_summary = scrape_opts.get('include_summary', False)
256
+ include_raw_content = scrape_opts.get('include_raw_content', False)
257
+ except json.JSONDecodeError:
258
+ pass
259
+
260
+ # Execute search
261
+ logger.info(f"Performing web search using Metaso, query: {self.tool.query}")
262
+ result = client.search(
263
+ query=self.tool.query,
264
+ scope=scope,
265
+ size=self.tool.limit,
266
+ include_summary=include_summary,
267
+ include_raw_content=include_raw_content
268
+ )
269
+
270
+ if not result.success:
271
+ return ToolResult(
272
+ success=False,
273
+ message=f"Metaso search failed: {result.error}",
274
+ content=[]
275
+ )
276
+
277
+ # Format search results
278
+ search_results = []
279
+ for webpage in result.webpages:
280
+ result_item = {
281
+ "type": "web",
282
+ "title": webpage.title,
283
+ "url": webpage.link,
284
+ "description": webpage.snippet,
285
+ "position": webpage.position,
286
+ "score": webpage.score,
287
+ "provider": "metaso",
288
+ "api_key_suffix": api_key[-4:] if len(api_key) > 4 else "****"
289
+ }
290
+
291
+ if webpage.date:
292
+ result_item["date"] = webpage.date
293
+ if webpage.authors:
294
+ result_item["authors"] = webpage.authors
295
+
296
+ search_results.append(result_item)
297
+
298
+ return ToolResult(
299
+ success=True,
300
+ message=f"Successfully found {len(search_results)} results (using Metaso)",
301
+ content=search_results
302
+ )
303
+
304
+ except Exception as e:
305
+ logger.error(f"Metaso search failed: {str(e)}")
306
+ return ToolResult(
307
+ success=False,
308
+ message=f"Metaso search failed: {str(e)}",
309
+ content=[]
310
+ )
311
+
312
+ def _search_with_firecrawl(self, api_key: str) -> ToolResult:
313
+ """Search using Firecrawl"""
314
+ try:
315
+ # Import Firecrawl SDK
316
+ try:
317
+ from firecrawl import Firecrawl
318
+ except ImportError:
319
+ return ToolResult(
320
+ success=False,
321
+ message="Firecrawl SDK not installed, please run: pip install firecrawl-py",
322
+ content=[]
323
+ )
324
+
325
+ # Initialize Firecrawl client
326
+ firecrawl = Firecrawl(api_key=api_key)
327
+
328
+ # Prepare search parameters
329
+ search_params = {
330
+ "query": self.tool.query,
331
+ "limit": self.tool.limit
332
+ }
333
+
334
+ # Add optional parameters
335
+ if self.tool.sources:
336
+ # Parse comma-separated sources string
337
+ sources_list = [s.strip() for s in self.tool.sources.split(',') if s.strip()]
338
+ search_params["sources"] = sources_list
339
+ if self.tool.scrape_options:
340
+ # Parse JSON format scrape_options string
341
+ try:
342
+ scrape_options_dict = json.loads(self.tool.scrape_options)
343
+ search_params["scrape_options"] = scrape_options_dict
344
+ except json.JSONDecodeError as e:
345
+ logger.warning(f"scrape_options JSON parsing failed: {e}, ignoring this parameter")
346
+ if self.tool.location:
347
+ search_params["location"] = self.tool.location
348
+ if self.tool.tbs:
349
+ search_params["tbs"] = self.tool.tbs
350
+
351
+ # Execute search
352
+ logger.info(f"Starting web search, query: {self.tool.query}")
353
+ results = firecrawl.search(**search_params)
354
+
355
+ # Check result type and success status
356
+ if not results:
357
+ return ToolResult(
358
+ success=False,
359
+ message="No results returned",
360
+ content=[]
361
+ )
362
+
363
+ # New version firecrawl returns SearchData object with different structure
364
+ if hasattr(results, 'success') and not results.success:
365
+ error_msg = getattr(results, 'error', 'Unknown error')
366
+ return ToolResult(
367
+ success=False,
368
+ message=f"Search failed: {error_msg}",
369
+ content=[]
370
+ )
371
+
372
+ # Format search results
373
+ search_results = []
374
+ # New version firecrawl returned data might be attribute instead of dict key
375
+ if hasattr(results, 'data'):
376
+ data = results.data
377
+ else:
378
+ data = results.get('data', {}) if hasattr(results, 'get') else {}
379
+
380
+ # If data is empty, log information for debugging
381
+ if not data or (isinstance(data, dict) and not data):
382
+ logger.info("Search returned empty data, possibly due to API quota limit or service status issues")
383
+
384
+ # Process web results - new version might be directly in data, not in data.web
385
+ web_results = []
386
+ if hasattr(data, 'web'):
387
+ web_results = data.web
388
+ elif isinstance(data, dict) and 'web' in data:
389
+ web_results = data['web']
390
+ elif isinstance(data, list):
391
+ # Might directly return result list
392
+ web_results = data
393
+
394
+ if web_results:
395
+ for item in web_results:
396
+ # Handle possible object or dictionary format
397
+ title = getattr(item, 'title', None) or (item.get('title', '') if hasattr(item, 'get') else '')
398
+ url = getattr(item, 'url', None) or (item.get('url', '') if hasattr(item, 'get') else '')
399
+ description = getattr(item, 'description', None) or (item.get('description', '') if hasattr(item, 'get') else '')
400
+ position = getattr(item, 'position', None) or (item.get('position', 0) if hasattr(item, 'get') else 0)
401
+
402
+ result_item = {
403
+ "type": "web",
404
+ "title": title,
405
+ "url": url,
406
+ "description": description,
407
+ "position": position,
408
+ "provider": "firecrawl",
409
+ "api_key_suffix": api_key[-4:] if len(api_key) > 4 else "****"
410
+ }
411
+
412
+ # If there is scraped content, add to results
413
+ markdown = getattr(item, 'markdown', None) or (item.get('markdown') if hasattr(item, 'get') else None)
414
+ if markdown:
415
+ result_item['content'] = markdown
416
+
417
+ links = getattr(item, 'links', None) or (item.get('links') if hasattr(item, 'get') else None)
418
+ if links:
419
+ result_item['links'] = links
420
+
421
+ metadata = getattr(item, 'metadata', None) or (item.get('metadata') if hasattr(item, 'get') else None)
422
+ if metadata:
423
+ result_item['metadata'] = metadata
424
+
425
+ search_results.append(result_item)
426
+
427
+ # Process news results
428
+ if isinstance(data, dict) and 'news' in data:
429
+ for item in data['news']:
430
+ result_item = {
431
+ "type": "news",
432
+ "title": item.get('title', ''),
433
+ "url": item.get('url', ''),
434
+ "snippet": item.get('snippet', ''),
435
+ "date": item.get('date', ''),
436
+ "position": item.get('position', 0),
437
+ "provider": "firecrawl",
438
+ "api_key_suffix": api_key[-4:] if len(api_key) > 4 else "****"
439
+ }
440
+ search_results.append(result_item)
441
+
442
+ # Process image results
443
+ if isinstance(data, dict) and 'images' in data:
444
+ for item in data['images']:
445
+ result_item = {
446
+ "type": "image",
447
+ "title": item.get('title', ''),
448
+ "imageUrl": item.get('imageUrl', ''),
449
+ "url": item.get('url', ''),
450
+ "imageWidth": item.get('imageWidth', 0),
451
+ "imageHeight": item.get('imageHeight', 0),
452
+ "position": item.get('position', 0),
453
+ "provider": "firecrawl",
454
+ "api_key_suffix": api_key[-4:] if len(api_key) > 4 else "****"
455
+ }
456
+ search_results.append(result_item)
457
+
458
+ return ToolResult(
459
+ success=True,
460
+ message=f"Successfully found {len(search_results)} results (using Firecrawl)",
461
+ content=search_results
462
+ )
463
+
464
+ except Exception as e:
465
+ logger.error(f"Firecrawl search failed: {str(e)}")
466
+ return ToolResult(
467
+ success=False,
468
+ message=f"Firecrawl search failed: {str(e)}",
469
+ content=[]
470
+ )
471
+
472
+ def _search_with_provider(self, provider: Dict[str, Any]) -> ToolResult:
473
+ """Search using specified provider"""
474
+ provider_type = provider['type']
475
+ api_key = provider['api_key']
476
+
477
+ if provider_type == 'bochaai':
478
+ return self._search_with_bochaai(api_key)
479
+ elif provider_type == 'metaso':
480
+ return self._search_with_metaso(api_key)
481
+ elif provider_type == 'firecrawl':
482
+ return self._search_with_firecrawl(api_key)
483
+ else:
484
+ return ToolResult(
485
+ success=False,
486
+ message=f"Unsupported provider type: {provider_type}",
487
+ content=[]
488
+ )
489
+
490
+ def _merge_results(self, results: List[ToolResult]) -> ToolResult:
491
+ """Merge multiple search results"""
492
+ successful_results = [r for r in results if r.success]
493
+ failed_results = [r for r in results if not r.success]
494
+
495
+ if not successful_results:
496
+ # All requests failed
497
+ error_messages = [r.message for r in failed_results]
498
+ return ToolResult(
499
+ success=False,
500
+ message=f"All search requests failed: {'; '.join(error_messages)}",
501
+ content=[]
502
+ )
503
+
504
+ # Merge successful results
505
+ all_content = []
506
+ total_results = 0
507
+ providers_used = set()
508
+
509
+ for result in successful_results:
510
+ if result.content:
511
+ all_content.extend(result.content)
512
+ total_results += len(result.content)
513
+ # 从结果中提取使用的提供商信息
514
+ for item in result.content:
515
+ if 'provider' in item:
516
+ providers_used.add(item['provider'])
517
+
518
+ # Remove duplicates (based on URL)
519
+ seen_urls = set()
520
+ unique_content = []
521
+ for item in all_content:
522
+ url = item.get('url', '')
523
+ if url and url not in seen_urls:
524
+ seen_urls.add(url)
525
+ unique_content.append(item)
526
+ elif not url: # If no URL, also keep
527
+ unique_content.append(item)
528
+
529
+ # Sort by position (if available)
530
+ unique_content.sort(key=lambda x: x.get('position', 999))
531
+
532
+ providers_str = ', '.join(sorted(providers_used)) if providers_used else 'unknown'
533
+ fail_count = len(failed_results)
534
+
535
+ message = f"Successfully found {len(unique_content)} results (using {providers_str})"
536
+ if fail_count > 0:
537
+ message += f", {fail_count} API keys failed"
538
+
539
+ return ToolResult(
540
+ success=True,
541
+ message=message,
542
+ content=unique_content
543
+ )
544
+
545
+ def resolve(self) -> ToolResult:
546
+ """Implement web search tool resolution logic with multi-key concurrency support"""
547
+ try:
548
+ # Get all available providers
549
+ providers = self._get_available_providers()
550
+
551
+ if not providers:
552
+ return ToolResult(
553
+ success=False,
554
+ message=f"No web search API key configured (BochaAI, Metaso, Firecrawl).",
555
+ content={}
556
+ )
557
+
558
+ logger.info(f"Found {len(providers)} available API configurations, starting concurrent search")
559
+
560
+ # If only one provider, call directly
561
+ if len(providers) == 1:
562
+ return self._search_with_provider(providers[0])
563
+
564
+ # Use thread pool for concurrent execution when multiple providers
565
+ results = []
566
+ max_workers = min(len(providers), 5) # Limit maximum concurrency
567
+
568
+ with ThreadPoolExecutor(max_workers=max_workers) as executor:
569
+ # Submit all tasks
570
+ future_to_provider = {
571
+ executor.submit(self._search_with_provider, provider): provider
572
+ for provider in providers
573
+ }
574
+
575
+ # Collect results
576
+ for future in as_completed(future_to_provider):
577
+ provider = future_to_provider[future]
578
+ try:
579
+ result = future.result(timeout=60) # 1 minute timeout
580
+ results.append(result)
581
+ logger.info(f"Provider {provider['type']} completed search")
582
+ except Exception as e:
583
+ logger.error(f"Provider {provider['type']} search exception: {str(e)}")
584
+ results.append(ToolResult(
585
+ success=False,
586
+ message=f"Provider {provider['type']} execution exception: {str(e)}",
587
+ content=[]
588
+ ))
589
+
590
+ # Merge results
591
+ return self._merge_results(results)
592
+
593
+ except Exception as e:
594
+ logger.error(f"Web search tool execution failed: {str(e)}")
595
+ return ToolResult(
596
+ success=False,
597
+ message=f"Web search tool execution failed: {str(e)}",
598
+ content=traceback.format_exc()
599
+ )
600
+