auto-coder 0.1.400__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 (579) 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-0.1.400.dist-info → auto_coder-2.0.0.dist-info}/WHEEL +1 -1
  5. {auto_coder-0.1.400.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 +25 -4
  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 +1029 -2310
  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 +1021 -372
  28. autocoder/chat_auto_coder_lang.py +23 -732
  29. autocoder/commands/auto_command.py +26 -9
  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/file_monitor/test_file_monitor.py +307 -0
  119. autocoder/common/git_utils.py +51 -10
  120. autocoder/common/global_cancel.py +15 -6
  121. autocoder/common/ignorefiles/test_ignore_file_utils.py +1 -1
  122. autocoder/common/international/__init__.py +31 -0
  123. autocoder/common/international/demo_international.py +92 -0
  124. autocoder/common/international/message_manager.py +157 -0
  125. autocoder/common/international/messages/__init__.py +56 -0
  126. autocoder/common/international/messages/async_command_messages.py +507 -0
  127. autocoder/common/international/messages/auto_coder_messages.py +2208 -0
  128. autocoder/common/international/messages/chat_auto_coder_messages.py +1547 -0
  129. autocoder/common/international/messages/command_help_messages.py +986 -0
  130. autocoder/common/international/messages/conversation_command_messages.py +191 -0
  131. autocoder/common/international/messages/git_helper_plugin_messages.py +159 -0
  132. autocoder/common/international/messages/queue_command_messages.py +751 -0
  133. autocoder/common/international/messages/rules_command_messages.py +77 -0
  134. autocoder/common/international/messages/sdk_messages.py +1707 -0
  135. autocoder/common/international/messages/token_helper_plugin_messages.py +361 -0
  136. autocoder/common/international/messages/tool_display_messages.py +1212 -0
  137. autocoder/common/international/messages/workflow_exception_messages.py +473 -0
  138. autocoder/common/international/test_international.py +612 -0
  139. autocoder/common/linter_core/__init__.py +28 -0
  140. autocoder/common/linter_core/base_linter.py +61 -0
  141. autocoder/common/linter_core/config_loader.py +271 -0
  142. autocoder/common/linter_core/formatters/__init__.py +0 -0
  143. autocoder/common/linter_core/formatters/base_formatter.py +38 -0
  144. autocoder/common/linter_core/formatters/raw_formatter.py +17 -0
  145. autocoder/common/linter_core/linter.py +166 -0
  146. autocoder/common/linter_core/linter_factory.py +216 -0
  147. autocoder/common/linter_core/linter_manager.py +333 -0
  148. autocoder/common/linter_core/linters/__init__.py +9 -0
  149. autocoder/common/linter_core/linters/java_linter.py +342 -0
  150. autocoder/common/linter_core/linters/python_linter.py +115 -0
  151. autocoder/common/linter_core/linters/typescript_linter.py +119 -0
  152. autocoder/common/linter_core/models/__init__.py +7 -0
  153. autocoder/common/linter_core/models/lint_result.py +91 -0
  154. autocoder/common/linter_core/models.py +33 -0
  155. autocoder/common/linter_core/tests/__init__.py +3 -0
  156. autocoder/common/linter_core/tests/test_config_loader.py +323 -0
  157. autocoder/common/linter_core/tests/test_config_loading.py +308 -0
  158. autocoder/common/linter_core/tests/test_factory_manager.py +234 -0
  159. autocoder/common/linter_core/tests/test_formatters.py +147 -0
  160. autocoder/common/linter_core/tests/test_integration.py +317 -0
  161. autocoder/common/linter_core/tests/test_java_linter.py +496 -0
  162. autocoder/common/linter_core/tests/test_linters.py +265 -0
  163. autocoder/common/linter_core/tests/test_models.py +81 -0
  164. autocoder/common/linter_core/tests/verify_config_loading.py +296 -0
  165. autocoder/common/linter_core/tests/verify_fixes.py +183 -0
  166. autocoder/common/llm_friendly_package/__init__.py +31 -0
  167. autocoder/common/llm_friendly_package/base_manager.py +102 -0
  168. autocoder/common/llm_friendly_package/docs_manager.py +121 -0
  169. autocoder/common/llm_friendly_package/library_manager.py +171 -0
  170. autocoder/common/{llm_friendly_package.py → llm_friendly_package/main_manager.py} +204 -231
  171. autocoder/common/llm_friendly_package/models.py +40 -0
  172. autocoder/common/llm_friendly_package/test_llm_friendly_package.py +536 -0
  173. autocoder/common/llms/__init__.py +15 -0
  174. autocoder/common/llms/demo_error_handling.py +85 -0
  175. autocoder/common/llms/factory.py +142 -0
  176. autocoder/common/llms/manager.py +264 -0
  177. autocoder/common/llms/pricing.py +121 -0
  178. autocoder/common/llms/registry.py +288 -0
  179. autocoder/common/llms/schema.py +77 -0
  180. autocoder/common/llms/simple_demo.py +45 -0
  181. autocoder/common/llms/test_quick_model.py +116 -0
  182. autocoder/common/llms/test_remove_functionality.py +182 -0
  183. autocoder/common/llms/tests/__init__.py +1 -0
  184. autocoder/common/llms/tests/test_manager.py +330 -0
  185. autocoder/common/llms/tests/test_registry.py +364 -0
  186. autocoder/common/mcp_tools/__init__.py +62 -0
  187. autocoder/common/{mcp_tools.py → mcp_tools/executor.py} +49 -40
  188. autocoder/common/{mcp_hub.py → mcp_tools/hub.py} +42 -68
  189. autocoder/common/{mcp_server_install.py → mcp_tools/installer.py} +16 -28
  190. autocoder/common/{mcp_server.py → mcp_tools/server.py} +176 -48
  191. autocoder/common/mcp_tools/test_keyboard_interrupt.py +93 -0
  192. autocoder/common/mcp_tools/test_mcp_tools.py +391 -0
  193. autocoder/common/{mcp_server_types.py → mcp_tools/types.py} +121 -48
  194. autocoder/common/mcp_tools/verify_functionality.py +202 -0
  195. autocoder/common/model_speed_tester.py +32 -26
  196. autocoder/common/priority_directory_finder/__init__.py +142 -0
  197. autocoder/common/priority_directory_finder/examples.py +230 -0
  198. autocoder/common/priority_directory_finder/finder.py +283 -0
  199. autocoder/common/priority_directory_finder/models.py +236 -0
  200. autocoder/common/priority_directory_finder/test_priority_directory_finder.py +431 -0
  201. autocoder/common/project_scanner/__init__.py +18 -0
  202. autocoder/common/project_scanner/compat.py +77 -0
  203. autocoder/common/project_scanner/scanner.py +436 -0
  204. autocoder/common/project_tracker/__init__.py +27 -0
  205. autocoder/common/project_tracker/api.py +228 -0
  206. autocoder/common/project_tracker/demo.py +272 -0
  207. autocoder/common/project_tracker/tracker.py +487 -0
  208. autocoder/common/project_tracker/types.py +53 -0
  209. autocoder/common/pruner/__init__.py +67 -0
  210. autocoder/common/pruner/agentic_conversation_pruner.py +746 -0
  211. autocoder/common/{context_pruner.py → pruner/context_pruner.py} +137 -40
  212. autocoder/common/pruner/conversation_message_ids_api.py +386 -0
  213. autocoder/common/pruner/conversation_message_ids_manager.py +347 -0
  214. autocoder/common/pruner/conversation_message_ids_pruner.py +473 -0
  215. autocoder/common/pruner/conversation_normalizer.py +347 -0
  216. autocoder/common/{conversation_pruner.py → pruner/conversation_pruner.py} +26 -6
  217. autocoder/common/pruner/test_agentic_conversation_pruner.py +784 -0
  218. autocoder/common/pruner/test_context_pruner.py +546 -0
  219. autocoder/common/pruner/test_conversation_normalizer.py +502 -0
  220. autocoder/common/pruner/test_tool_content_detector.py +324 -0
  221. autocoder/common/pruner/tool_content_detector.py +227 -0
  222. autocoder/common/pruner/tools/__init__.py +18 -0
  223. autocoder/common/pruner/tools/query_message_ids.py +264 -0
  224. autocoder/common/pruner/tools/test_agentic_pruning_logic.py +432 -0
  225. autocoder/common/pruner/tools/test_message_ids_pruning_only.py +192 -0
  226. autocoder/common/pull_requests/__init__.py +9 -1
  227. autocoder/common/pull_requests/utils.py +122 -1
  228. autocoder/common/rag_manager/rag_manager.py +36 -40
  229. autocoder/common/rulefiles/__init__.py +53 -1
  230. autocoder/common/rulefiles/api.py +250 -0
  231. autocoder/common/rulefiles/core/__init__.py +14 -0
  232. autocoder/common/rulefiles/core/manager.py +241 -0
  233. autocoder/common/rulefiles/core/selector.py +805 -0
  234. autocoder/common/rulefiles/models/__init__.py +20 -0
  235. autocoder/common/rulefiles/models/index.py +16 -0
  236. autocoder/common/rulefiles/models/init_rule.py +18 -0
  237. autocoder/common/rulefiles/models/rule_file.py +18 -0
  238. autocoder/common/rulefiles/models/rule_relevance.py +14 -0
  239. autocoder/common/rulefiles/models/summary.py +16 -0
  240. autocoder/common/rulefiles/test_rulefiles.py +776 -0
  241. autocoder/common/rulefiles/utils/__init__.py +34 -0
  242. autocoder/common/rulefiles/utils/monitor.py +86 -0
  243. autocoder/common/rulefiles/utils/parser.py +230 -0
  244. autocoder/common/save_formatted_log.py +67 -10
  245. autocoder/common/search_replace.py +8 -1
  246. autocoder/common/search_replace_patch/__init__.py +24 -0
  247. autocoder/common/search_replace_patch/base.py +115 -0
  248. autocoder/common/search_replace_patch/manager.py +248 -0
  249. autocoder/common/search_replace_patch/patch_replacer.py +304 -0
  250. autocoder/common/search_replace_patch/similarity_replacer.py +306 -0
  251. autocoder/common/search_replace_patch/string_replacer.py +181 -0
  252. autocoder/common/search_replace_patch/tests/__init__.py +3 -0
  253. autocoder/common/search_replace_patch/tests/run_tests.py +126 -0
  254. autocoder/common/search_replace_patch/tests/test_base.py +188 -0
  255. autocoder/common/search_replace_patch/tests/test_empty_line_insert.py +233 -0
  256. autocoder/common/search_replace_patch/tests/test_integration.py +389 -0
  257. autocoder/common/search_replace_patch/tests/test_manager.py +351 -0
  258. autocoder/common/search_replace_patch/tests/test_patch_replacer.py +316 -0
  259. autocoder/common/search_replace_patch/tests/test_regex_replacer.py +306 -0
  260. autocoder/common/search_replace_patch/tests/test_similarity_replacer.py +384 -0
  261. autocoder/common/shell_commands/__init__.py +197 -0
  262. autocoder/common/shell_commands/background_process_notifier.py +346 -0
  263. autocoder/common/shell_commands/command_executor.py +1127 -0
  264. autocoder/common/shell_commands/error_recovery.py +541 -0
  265. autocoder/common/shell_commands/exceptions.py +120 -0
  266. autocoder/common/shell_commands/interactive_executor.py +476 -0
  267. autocoder/common/shell_commands/interactive_pexpect_process.py +623 -0
  268. autocoder/common/shell_commands/interactive_process.py +744 -0
  269. autocoder/common/shell_commands/interactive_session_manager.py +1014 -0
  270. autocoder/common/shell_commands/monitoring.py +529 -0
  271. autocoder/common/shell_commands/process_cleanup.py +386 -0
  272. autocoder/common/shell_commands/process_manager.py +606 -0
  273. autocoder/common/shell_commands/test_interactive_pexpect_process.py +281 -0
  274. autocoder/common/shell_commands/tests/__init__.py +6 -0
  275. autocoder/common/shell_commands/tests/conftest.py +118 -0
  276. autocoder/common/shell_commands/tests/test_background_process_notifier.py +703 -0
  277. autocoder/common/shell_commands/tests/test_command_executor.py +448 -0
  278. autocoder/common/shell_commands/tests/test_error_recovery.py +305 -0
  279. autocoder/common/shell_commands/tests/test_exceptions.py +299 -0
  280. autocoder/common/shell_commands/tests/test_execute_batch.py +588 -0
  281. autocoder/common/shell_commands/tests/test_indented_batch_commands.py +244 -0
  282. autocoder/common/shell_commands/tests/test_integration.py +664 -0
  283. autocoder/common/shell_commands/tests/test_monitoring.py +546 -0
  284. autocoder/common/shell_commands/tests/test_performance.py +632 -0
  285. autocoder/common/shell_commands/tests/test_process_cleanup.py +397 -0
  286. autocoder/common/shell_commands/tests/test_process_manager.py +606 -0
  287. autocoder/common/shell_commands/tests/test_timeout_config.py +343 -0
  288. autocoder/common/shell_commands/tests/test_timeout_manager.py +520 -0
  289. autocoder/common/shell_commands/timeout_config.py +315 -0
  290. autocoder/common/shell_commands/timeout_manager.py +352 -0
  291. autocoder/common/terminal_paste/__init__.py +14 -0
  292. autocoder/common/terminal_paste/demo.py +145 -0
  293. autocoder/common/terminal_paste/demo_paste_functionality.py +95 -0
  294. autocoder/common/terminal_paste/paste_handler.py +200 -0
  295. autocoder/common/terminal_paste/paste_manager.py +118 -0
  296. autocoder/common/terminal_paste/tests/__init__.py +1 -0
  297. autocoder/common/terminal_paste/tests/test_paste_handler.py +182 -0
  298. autocoder/common/terminal_paste/tests/test_paste_manager.py +126 -0
  299. autocoder/common/terminal_paste/utils.py +163 -0
  300. autocoder/common/test_autocoder_args.py +232 -0
  301. autocoder/common/test_env_manager.py +173 -0
  302. autocoder/common/test_env_manager_integration.py +159 -0
  303. autocoder/common/text_similarity/__init__.py +9 -0
  304. autocoder/common/text_similarity/demo.py +216 -0
  305. autocoder/common/text_similarity/examples.py +266 -0
  306. autocoder/common/text_similarity/test_text_similarity.py +306 -0
  307. autocoder/common/text_similarity/text_similarity.py +194 -0
  308. autocoder/common/text_similarity/utils.py +125 -0
  309. autocoder/common/todos/__init__.py +61 -0
  310. autocoder/common/todos/cache/__init__.py +16 -0
  311. autocoder/common/todos/cache/base_cache.py +89 -0
  312. autocoder/common/todos/cache/cache_manager.py +228 -0
  313. autocoder/common/todos/cache/memory_cache.py +225 -0
  314. autocoder/common/todos/config.py +155 -0
  315. autocoder/common/todos/exceptions.py +35 -0
  316. autocoder/common/todos/get_todo_manager.py +161 -0
  317. autocoder/common/todos/manager.py +537 -0
  318. autocoder/common/todos/models.py +239 -0
  319. autocoder/common/todos/storage/__init__.py +14 -0
  320. autocoder/common/todos/storage/base_storage.py +76 -0
  321. autocoder/common/todos/storage/file_storage.py +278 -0
  322. autocoder/common/tokens/__init__.py +15 -0
  323. autocoder/common/tokens/counter.py +44 -2
  324. autocoder/common/tools_manager/__init__.py +17 -0
  325. autocoder/common/tools_manager/examples.py +162 -0
  326. autocoder/common/tools_manager/manager.py +385 -0
  327. autocoder/common/tools_manager/models.py +39 -0
  328. autocoder/common/tools_manager/test_tools_manager.py +303 -0
  329. autocoder/common/tools_manager/utils.py +191 -0
  330. autocoder/common/v2/agent/agentic_callbacks.py +270 -0
  331. autocoder/common/v2/agent/agentic_edit.py +2729 -2052
  332. autocoder/common/v2/agent/agentic_edit_change_manager.py +474 -0
  333. autocoder/common/v2/agent/agentic_edit_tools/__init__.py +43 -2
  334. autocoder/common/v2/agent/agentic_edit_tools/ac_mod_list_tool_resolver.py +279 -0
  335. autocoder/common/v2/agent/agentic_edit_tools/ac_mod_read_tool_resolver.py +40 -0
  336. autocoder/common/v2/agent/agentic_edit_tools/ac_mod_write_tool_resolver.py +52 -0
  337. autocoder/common/v2/agent/agentic_edit_tools/ask_followup_question_tool_resolver.py +8 -0
  338. autocoder/common/v2/agent/agentic_edit_tools/background_task_tool_resolver.py +1167 -0
  339. autocoder/common/v2/agent/agentic_edit_tools/base_tool_resolver.py +2 -2
  340. autocoder/common/v2/agent/agentic_edit_tools/conversation_message_ids_read_tool_resolver.py +214 -0
  341. autocoder/common/v2/agent/agentic_edit_tools/conversation_message_ids_write_tool_resolver.py +299 -0
  342. autocoder/common/v2/agent/agentic_edit_tools/count_tokens_tool_resolver.py +290 -0
  343. autocoder/common/v2/agent/agentic_edit_tools/execute_command_tool_resolver.py +565 -30
  344. autocoder/common/v2/agent/agentic_edit_tools/execute_workflow_tool_resolver.py +485 -0
  345. autocoder/common/v2/agent/agentic_edit_tools/extract_to_text_tool_resolver.py +225 -0
  346. autocoder/common/v2/agent/agentic_edit_tools/lint_report.py +79 -0
  347. autocoder/common/v2/agent/agentic_edit_tools/linter_config_models.py +343 -0
  348. autocoder/common/v2/agent/agentic_edit_tools/linter_enabled_tool_resolver.py +189 -0
  349. autocoder/common/v2/agent/agentic_edit_tools/list_files_tool_resolver.py +169 -101
  350. autocoder/common/v2/agent/agentic_edit_tools/load_extra_document_tool_resolver.py +349 -0
  351. autocoder/common/v2/agent/agentic_edit_tools/read_file_tool_resolver.py +244 -51
  352. autocoder/common/v2/agent/agentic_edit_tools/replace_in_file_tool_resolver.py +667 -147
  353. autocoder/common/v2/agent/agentic_edit_tools/run_named_subagents_tool_resolver.py +691 -0
  354. autocoder/common/v2/agent/agentic_edit_tools/search_files_tool_resolver.py +409 -140
  355. autocoder/common/v2/agent/agentic_edit_tools/session_interactive_tool_resolver.py +115 -0
  356. autocoder/common/v2/agent/agentic_edit_tools/session_start_tool_resolver.py +190 -0
  357. autocoder/common/v2/agent/agentic_edit_tools/session_stop_tool_resolver.py +76 -0
  358. autocoder/common/v2/agent/agentic_edit_tools/test_write_to_file_tool_resolver.py +209 -194
  359. autocoder/common/v2/agent/agentic_edit_tools/todo_read_tool_resolver.py +135 -0
  360. autocoder/common/v2/agent/agentic_edit_tools/todo_write_tool_resolver.py +328 -0
  361. autocoder/common/v2/agent/agentic_edit_tools/use_mcp_tool_resolver.py +2 -2
  362. autocoder/common/v2/agent/agentic_edit_tools/web_crawl_tool_resolver.py +557 -0
  363. autocoder/common/v2/agent/agentic_edit_tools/web_search_tool_resolver.py +600 -0
  364. autocoder/common/v2/agent/agentic_edit_tools/write_to_file_tool_resolver.py +56 -121
  365. autocoder/common/v2/agent/agentic_edit_types.py +386 -10
  366. autocoder/common/v2/agent/runner/__init__.py +31 -0
  367. autocoder/common/v2/agent/runner/base_runner.py +92 -0
  368. autocoder/common/v2/agent/runner/file_based_event_runner.py +217 -0
  369. autocoder/common/v2/agent/runner/sdk_runner.py +182 -0
  370. autocoder/common/v2/agent/runner/terminal_runner.py +396 -0
  371. autocoder/common/v2/agent/runner/tool_display.py +589 -0
  372. autocoder/common/v2/agent/test_agentic_callbacks.py +265 -0
  373. autocoder/common/v2/agent/test_agentic_edit.py +194 -0
  374. autocoder/common/v2/agent/tool_caller/__init__.py +24 -0
  375. autocoder/common/v2/agent/tool_caller/default_tool_resolver_map.py +135 -0
  376. autocoder/common/v2/agent/tool_caller/integration_test.py +172 -0
  377. autocoder/common/v2/agent/tool_caller/plugins/__init__.py +14 -0
  378. autocoder/common/v2/agent/tool_caller/plugins/base_plugin.py +126 -0
  379. autocoder/common/v2/agent/tool_caller/plugins/examples/__init__.py +13 -0
  380. autocoder/common/v2/agent/tool_caller/plugins/examples/logging_plugin.py +164 -0
  381. autocoder/common/v2/agent/tool_caller/plugins/examples/security_filter_plugin.py +198 -0
  382. autocoder/common/v2/agent/tool_caller/plugins/plugin_interface.py +141 -0
  383. autocoder/common/v2/agent/tool_caller/test_tool_caller.py +278 -0
  384. autocoder/common/v2/agent/tool_caller/tool_call_plugin_manager.py +331 -0
  385. autocoder/common/v2/agent/tool_caller/tool_caller.py +337 -0
  386. autocoder/common/v2/agent/tool_caller/usage_example.py +193 -0
  387. autocoder/common/v2/code_agentic_editblock_manager.py +4 -4
  388. autocoder/common/v2/code_auto_generate.py +136 -78
  389. autocoder/common/v2/code_auto_generate_diff.py +135 -79
  390. autocoder/common/v2/code_auto_generate_editblock.py +174 -99
  391. autocoder/common/v2/code_auto_generate_strict_diff.py +151 -71
  392. autocoder/common/v2/code_auto_merge.py +1 -1
  393. autocoder/common/v2/code_auto_merge_editblock.py +13 -1
  394. autocoder/common/v2/code_diff_manager.py +3 -3
  395. autocoder/common/v2/code_editblock_manager.py +4 -14
  396. autocoder/common/v2/code_manager.py +1 -1
  397. autocoder/common/v2/code_strict_diff_manager.py +2 -2
  398. autocoder/common/wrap_llm_hint/__init__.py +10 -0
  399. autocoder/common/wrap_llm_hint/test_wrap_llm_hint.py +1067 -0
  400. autocoder/common/wrap_llm_hint/utils.py +432 -0
  401. autocoder/common/wrap_llm_hint/wrap_llm_hint.py +323 -0
  402. autocoder/completer/__init__.py +8 -0
  403. autocoder/completer/command_completer_v2.py +1051 -0
  404. autocoder/default_project/__init__.py +501 -0
  405. autocoder/dispacher/__init__.py +4 -12
  406. autocoder/dispacher/actions/action.py +165 -7
  407. autocoder/dispacher/actions/plugins/action_regex_project.py +2 -2
  408. autocoder/index/entry.py +117 -125
  409. autocoder/{agent → index/filter}/agentic_filter.py +323 -334
  410. autocoder/index/filter/normal_filter.py +5 -11
  411. autocoder/index/filter/quick_filter.py +1 -1
  412. autocoder/index/index.py +36 -9
  413. autocoder/index/tests/__init__.py +1 -0
  414. autocoder/index/tests/run_tests.py +195 -0
  415. autocoder/index/tests/test_entry.py +303 -0
  416. autocoder/index/tests/test_index_manager.py +314 -0
  417. autocoder/index/tests/test_module_integration.py +300 -0
  418. autocoder/index/tests/test_symbols_utils.py +183 -0
  419. autocoder/inner/__init__.py +4 -0
  420. autocoder/inner/agentic.py +932 -0
  421. autocoder/inner/async_command_handler.py +992 -0
  422. autocoder/inner/conversation_command_handlers.py +623 -0
  423. autocoder/inner/merge_command_handler.py +213 -0
  424. autocoder/inner/queue_command_handler.py +684 -0
  425. autocoder/models.py +95 -266
  426. autocoder/plugins/git_helper_plugin.py +31 -29
  427. autocoder/plugins/token_helper_plugin.py +156 -37
  428. autocoder/pyproject/__init__.py +32 -29
  429. autocoder/rag/agentic_rag.py +215 -75
  430. autocoder/rag/cache/simple_cache.py +1 -2
  431. autocoder/rag/loaders/image_loader.py +1 -1
  432. autocoder/rag/long_context_rag.py +42 -26
  433. autocoder/rag/qa_conversation_strategy.py +1 -1
  434. autocoder/rag/terminal/__init__.py +17 -0
  435. autocoder/rag/terminal/args.py +581 -0
  436. autocoder/rag/terminal/bootstrap.py +61 -0
  437. autocoder/rag/terminal/command_handlers.py +653 -0
  438. autocoder/rag/terminal/formatters/__init__.py +20 -0
  439. autocoder/rag/terminal/formatters/base.py +70 -0
  440. autocoder/rag/terminal/formatters/json_format.py +66 -0
  441. autocoder/rag/terminal/formatters/stream_json.py +95 -0
  442. autocoder/rag/terminal/formatters/text.py +28 -0
  443. autocoder/rag/terminal/init.py +120 -0
  444. autocoder/rag/terminal/utils.py +106 -0
  445. autocoder/rag/test_agentic_rag.py +389 -0
  446. autocoder/rag/test_doc_filter.py +3 -3
  447. autocoder/rag/test_long_context_rag.py +1 -1
  448. autocoder/rag/test_token_limiter.py +517 -10
  449. autocoder/rag/token_counter.py +3 -0
  450. autocoder/rag/token_limiter.py +19 -15
  451. autocoder/rag/tools/__init__.py +26 -2
  452. autocoder/rag/tools/bochaai_example.py +343 -0
  453. autocoder/rag/tools/bochaai_sdk.py +541 -0
  454. autocoder/rag/tools/metaso_example.py +268 -0
  455. autocoder/rag/tools/metaso_sdk.py +417 -0
  456. autocoder/rag/tools/recall_tool.py +28 -7
  457. autocoder/rag/tools/run_integration_tests.py +204 -0
  458. autocoder/rag/tools/test_all_providers.py +318 -0
  459. autocoder/rag/tools/test_bochaai_integration.py +482 -0
  460. autocoder/rag/tools/test_final_integration.py +215 -0
  461. autocoder/rag/tools/test_metaso_integration.py +424 -0
  462. autocoder/rag/tools/test_metaso_real.py +171 -0
  463. autocoder/rag/tools/test_web_crawl_tool.py +639 -0
  464. autocoder/rag/tools/test_web_search_tool.py +509 -0
  465. autocoder/rag/tools/todo_read_tool.py +202 -0
  466. autocoder/rag/tools/todo_write_tool.py +412 -0
  467. autocoder/rag/tools/web_crawl_tool.py +634 -0
  468. autocoder/rag/tools/web_search_tool.py +558 -0
  469. autocoder/rag/tools/web_tools_example.py +119 -0
  470. autocoder/rag/types.py +16 -0
  471. autocoder/rag/variable_holder.py +4 -2
  472. autocoder/rags.py +86 -79
  473. autocoder/regexproject/__init__.py +23 -21
  474. autocoder/run_context.py +9 -0
  475. autocoder/sdk/__init__.py +50 -161
  476. autocoder/sdk/api.py +370 -0
  477. autocoder/sdk/async_runner/__init__.py +26 -0
  478. autocoder/sdk/async_runner/async_executor.py +650 -0
  479. autocoder/sdk/async_runner/async_handler.py +356 -0
  480. autocoder/sdk/async_runner/markdown_processor.py +595 -0
  481. autocoder/sdk/async_runner/task_metadata.py +284 -0
  482. autocoder/sdk/async_runner/worktree_manager.py +438 -0
  483. autocoder/sdk/cli/__init__.py +2 -5
  484. autocoder/sdk/cli/formatters.py +28 -204
  485. autocoder/sdk/cli/handlers.py +77 -44
  486. autocoder/sdk/cli/main.py +158 -170
  487. autocoder/sdk/cli/options.py +95 -22
  488. autocoder/sdk/constants.py +139 -51
  489. autocoder/sdk/core/auto_coder_core.py +484 -267
  490. autocoder/sdk/core/bridge.py +298 -118
  491. autocoder/sdk/exceptions.py +18 -12
  492. autocoder/sdk/formatters/__init__.py +19 -0
  493. autocoder/sdk/formatters/input.py +64 -0
  494. autocoder/sdk/formatters/output.py +247 -0
  495. autocoder/sdk/formatters/stream.py +54 -0
  496. autocoder/sdk/models/__init__.py +6 -5
  497. autocoder/sdk/models/options.py +55 -18
  498. autocoder/sdk/utils/formatters.py +27 -195
  499. autocoder/suffixproject/__init__.py +28 -25
  500. autocoder/terminal/__init__.py +14 -0
  501. autocoder/terminal/app.py +454 -0
  502. autocoder/terminal/args.py +32 -0
  503. autocoder/terminal/bootstrap.py +178 -0
  504. autocoder/terminal/command_processor.py +521 -0
  505. autocoder/terminal/command_registry.py +57 -0
  506. autocoder/terminal/help.py +97 -0
  507. autocoder/terminal/tasks/__init__.py +5 -0
  508. autocoder/terminal/tasks/background.py +77 -0
  509. autocoder/terminal/tasks/task_event.py +70 -0
  510. autocoder/terminal/ui/__init__.py +13 -0
  511. autocoder/terminal/ui/completer.py +268 -0
  512. autocoder/terminal/ui/keybindings.py +75 -0
  513. autocoder/terminal/ui/session.py +41 -0
  514. autocoder/terminal/ui/toolbar.py +64 -0
  515. autocoder/terminal/utils/__init__.py +13 -0
  516. autocoder/terminal/utils/errors.py +18 -0
  517. autocoder/terminal/utils/paths.py +19 -0
  518. autocoder/terminal/utils/shell.py +43 -0
  519. autocoder/terminal_v3/__init__.py +10 -0
  520. autocoder/terminal_v3/app.py +201 -0
  521. autocoder/terminal_v3/handlers/__init__.py +5 -0
  522. autocoder/terminal_v3/handlers/command_handler.py +131 -0
  523. autocoder/terminal_v3/models/__init__.py +6 -0
  524. autocoder/terminal_v3/models/conversation_buffer.py +214 -0
  525. autocoder/terminal_v3/models/message.py +50 -0
  526. autocoder/terminal_v3/models/tool_display.py +247 -0
  527. autocoder/terminal_v3/ui/__init__.py +7 -0
  528. autocoder/terminal_v3/ui/keybindings.py +56 -0
  529. autocoder/terminal_v3/ui/layout.py +141 -0
  530. autocoder/terminal_v3/ui/styles.py +43 -0
  531. autocoder/tsproject/__init__.py +23 -23
  532. autocoder/utils/auto_coder_utils/chat_stream_out.py +1 -1
  533. autocoder/utils/llms.py +88 -80
  534. autocoder/utils/math_utils.py +101 -0
  535. autocoder/utils/model_provider_selector.py +16 -4
  536. autocoder/utils/operate_config_api.py +33 -5
  537. autocoder/utils/thread_utils.py +2 -2
  538. autocoder/version.py +4 -2
  539. autocoder/workflow_agents/__init__.py +84 -0
  540. autocoder/workflow_agents/agent.py +143 -0
  541. autocoder/workflow_agents/exceptions.py +573 -0
  542. autocoder/workflow_agents/executor.py +489 -0
  543. autocoder/workflow_agents/loader.py +737 -0
  544. autocoder/workflow_agents/runner.py +267 -0
  545. autocoder/workflow_agents/types.py +172 -0
  546. autocoder/workflow_agents/utils.py +434 -0
  547. autocoder/workflow_agents/workflow_manager.py +211 -0
  548. auto_coder-0.1.400.dist-info/METADATA +0 -396
  549. auto_coder-0.1.400.dist-info/RECORD +0 -425
  550. auto_coder-0.1.400.dist-info/licenses/LICENSE +0 -201
  551. autocoder/auto_coder_server.py +0 -672
  552. autocoder/benchmark.py +0 -138
  553. autocoder/common/ac_style_command_parser/example.py +0 -7
  554. autocoder/common/cleaner.py +0 -31
  555. autocoder/common/command_completer_v2.py +0 -615
  556. autocoder/common/directory_cache/__init__.py +0 -1
  557. autocoder/common/directory_cache/cache.py +0 -192
  558. autocoder/common/directory_cache/test_cache.py +0 -190
  559. autocoder/common/file_checkpoint/examples.py +0 -217
  560. autocoder/common/llm_friendly_package_example.py +0 -138
  561. autocoder/common/llm_friendly_package_test.py +0 -63
  562. autocoder/common/pull_requests/test_module.py +0 -1
  563. autocoder/common/rulefiles/autocoderrules_utils.py +0 -484
  564. autocoder/common/text.py +0 -30
  565. autocoder/common/v2/agent/agentic_edit_tools/list_package_info_tool_resolver.py +0 -42
  566. autocoder/common/v2/agent/agentic_edit_tools/test_execute_command_tool_resolver.py +0 -70
  567. autocoder/common/v2/agent/agentic_edit_tools/test_search_files_tool_resolver.py +0 -163
  568. autocoder/common/v2/agent/agentic_tool_display.py +0 -183
  569. autocoder/plugins/dynamic_completion_example.py +0 -148
  570. autocoder/plugins/sample_plugin.py +0 -160
  571. autocoder/sdk/cli/__main__.py +0 -26
  572. autocoder/sdk/cli/completion_wrapper.py +0 -38
  573. autocoder/sdk/cli/install_completion.py +0 -301
  574. autocoder/sdk/models/messages.py +0 -209
  575. autocoder/sdk/session/__init__.py +0 -32
  576. autocoder/sdk/session/session.py +0 -106
  577. autocoder/sdk/session/session_manager.py +0 -56
  578. {auto_coder-0.1.400.dist-info → auto_coder-2.0.0.dist-info}/top_level.txt +0 -0
  579. /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
+