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

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

Potentially problematic release.


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

Files changed (574) hide show
  1. auto_coder-2.0.1.dist-info/LICENSE +158 -0
  2. auto_coder-2.0.1.dist-info/METADATA +558 -0
  3. auto_coder-2.0.1.dist-info/RECORD +795 -0
  4. {auto_coder-1.0.0.dist-info → auto_coder-2.0.1.dist-info}/WHEEL +1 -1
  5. {auto_coder-1.0.0.dist-info → auto_coder-2.0.1.dist-info}/entry_points.txt +3 -3
  6. autocoder/__init__.py +31 -0
  7. autocoder/agent/auto_filegroup.py +32 -13
  8. autocoder/agent/auto_learn_from_commit.py +9 -1
  9. autocoder/agent/base_agentic/__init__.py +3 -0
  10. autocoder/agent/base_agentic/agent_hub.py +1 -1
  11. autocoder/agent/base_agentic/base_agent.py +235 -136
  12. autocoder/agent/base_agentic/default_tools.py +119 -118
  13. autocoder/agent/base_agentic/test_base_agent.py +1 -1
  14. autocoder/agent/base_agentic/tool_registry.py +32 -20
  15. autocoder/agent/base_agentic/tools/read_file_tool_resolver.py +24 -3
  16. autocoder/agent/base_agentic/tools/write_to_file_tool_resolver.py +24 -11
  17. autocoder/agent/base_agentic/types.py +42 -0
  18. autocoder/agent/entry_command_agent/chat.py +77 -73
  19. autocoder/auto_coder.py +31 -40
  20. autocoder/auto_coder_rag.py +11 -1084
  21. autocoder/auto_coder_runner.py +962 -2345
  22. autocoder/auto_coder_terminal.py +26 -0
  23. autocoder/auto_coder_terminal_v3.py +190 -0
  24. autocoder/chat/conf_command.py +224 -124
  25. autocoder/chat/models_command.py +361 -299
  26. autocoder/chat/rules_command.py +79 -31
  27. autocoder/chat_auto_coder.py +988 -398
  28. autocoder/chat_auto_coder_lang.py +23 -732
  29. autocoder/commands/auto_command.py +25 -8
  30. autocoder/commands/auto_web.py +1 -1
  31. autocoder/commands/tools.py +44 -44
  32. autocoder/common/__init__.py +150 -128
  33. autocoder/common/ac_style_command_parser/__init__.py +39 -2
  34. autocoder/common/ac_style_command_parser/config.py +422 -0
  35. autocoder/common/ac_style_command_parser/parser.py +292 -78
  36. autocoder/common/ac_style_command_parser/test_parser.py +241 -16
  37. autocoder/common/ac_style_command_parser/test_typed_parser.py +342 -0
  38. autocoder/common/ac_style_command_parser/typed_parser.py +653 -0
  39. autocoder/common/action_yml_file_manager.py +25 -13
  40. autocoder/common/agent_events/__init__.py +52 -0
  41. autocoder/common/agent_events/agent_event_emitter.py +193 -0
  42. autocoder/common/agent_events/event_factory.py +177 -0
  43. autocoder/common/agent_events/examples.py +307 -0
  44. autocoder/common/agent_events/types.py +113 -0
  45. autocoder/common/agent_events/utils.py +68 -0
  46. autocoder/common/agent_hooks/__init__.py +44 -0
  47. autocoder/common/agent_hooks/examples.py +582 -0
  48. autocoder/common/agent_hooks/hook_executor.py +217 -0
  49. autocoder/common/agent_hooks/hook_manager.py +288 -0
  50. autocoder/common/agent_hooks/types.py +133 -0
  51. autocoder/common/agent_hooks/utils.py +99 -0
  52. autocoder/common/agent_query_queue/queue_executor.py +324 -0
  53. autocoder/common/agent_query_queue/queue_manager.py +325 -0
  54. autocoder/common/agents/__init__.py +11 -0
  55. autocoder/common/agents/agent_manager.py +323 -0
  56. autocoder/common/agents/agent_parser.py +189 -0
  57. autocoder/common/agents/example_usage.py +344 -0
  58. autocoder/common/agents/integration_example.py +330 -0
  59. autocoder/common/agents/test_agent_parser.py +545 -0
  60. autocoder/common/async_utils.py +101 -0
  61. autocoder/common/auto_coder_lang.py +23 -972
  62. autocoder/common/autocoderargs_parser/__init__.py +14 -0
  63. autocoder/common/autocoderargs_parser/parser.py +184 -0
  64. autocoder/common/autocoderargs_parser/tests/__init__.py +1 -0
  65. autocoder/common/autocoderargs_parser/tests/test_args_parser.py +235 -0
  66. autocoder/common/autocoderargs_parser/tests/test_token_parser.py +195 -0
  67. autocoder/common/autocoderargs_parser/token_parser.py +290 -0
  68. autocoder/common/buildin_tokenizer.py +2 -4
  69. autocoder/common/code_auto_generate.py +149 -74
  70. autocoder/common/code_auto_generate_diff.py +163 -70
  71. autocoder/common/code_auto_generate_editblock.py +179 -89
  72. autocoder/common/code_auto_generate_strict_diff.py +167 -72
  73. autocoder/common/code_auto_merge_editblock.py +13 -6
  74. autocoder/common/code_modification_ranker.py +1 -1
  75. autocoder/common/command_completer.py +3 -3
  76. autocoder/common/command_file_manager/manager.py +183 -47
  77. autocoder/common/command_file_manager/test_command_file_manager.py +507 -0
  78. autocoder/common/command_templates.py +1 -1
  79. autocoder/common/conf_utils.py +2 -4
  80. autocoder/common/conversations/config.py +11 -3
  81. autocoder/common/conversations/get_conversation_manager.py +100 -2
  82. autocoder/common/conversations/llm_stats_models.py +264 -0
  83. autocoder/common/conversations/manager.py +112 -28
  84. autocoder/common/conversations/models.py +16 -2
  85. autocoder/common/conversations/storage/index_manager.py +134 -10
  86. autocoder/common/core_config/__init__.py +63 -0
  87. autocoder/common/core_config/agentic_mode_manager.py +109 -0
  88. autocoder/common/core_config/base_manager.py +123 -0
  89. autocoder/common/core_config/compatibility.py +151 -0
  90. autocoder/common/core_config/config_manager.py +156 -0
  91. autocoder/common/core_config/conversation_manager.py +31 -0
  92. autocoder/common/core_config/exclude_manager.py +72 -0
  93. autocoder/common/core_config/file_manager.py +177 -0
  94. autocoder/common/core_config/human_as_model_manager.py +129 -0
  95. autocoder/common/core_config/lib_manager.py +54 -0
  96. autocoder/common/core_config/main_manager.py +81 -0
  97. autocoder/common/core_config/mode_manager.py +126 -0
  98. autocoder/common/core_config/models.py +70 -0
  99. autocoder/common/core_config/test_memory_manager.py +1056 -0
  100. autocoder/common/env_manager.py +282 -0
  101. autocoder/common/env_manager_usage_example.py +211 -0
  102. autocoder/common/file_checkpoint/conversation_checkpoint.py +19 -19
  103. autocoder/common/file_checkpoint/manager.py +264 -48
  104. autocoder/common/file_checkpoint/test_backup.py +1 -18
  105. autocoder/common/file_checkpoint/test_manager.py +270 -1
  106. autocoder/common/file_checkpoint/test_store.py +1 -17
  107. autocoder/common/file_handler/__init__.py +23 -0
  108. autocoder/common/file_handler/active_context_handler.py +159 -0
  109. autocoder/common/file_handler/add_files_handler.py +409 -0
  110. autocoder/common/file_handler/chat_handler.py +180 -0
  111. autocoder/common/file_handler/coding_handler.py +409 -0
  112. autocoder/common/file_handler/commit_handler.py +200 -0
  113. autocoder/common/file_handler/lib_handler.py +156 -0
  114. autocoder/common/file_handler/list_files_handler.py +111 -0
  115. autocoder/common/file_handler/mcp_handler.py +268 -0
  116. autocoder/common/file_handler/models_handler.py +493 -0
  117. autocoder/common/file_handler/remove_files_handler.py +172 -0
  118. autocoder/common/git_utils.py +44 -8
  119. autocoder/common/global_cancel.py +15 -6
  120. autocoder/common/ignorefiles/test_ignore_file_utils.py +1 -1
  121. autocoder/common/international/__init__.py +31 -0
  122. autocoder/common/international/demo_international.py +92 -0
  123. autocoder/common/international/message_manager.py +157 -0
  124. autocoder/common/international/messages/__init__.py +56 -0
  125. autocoder/common/international/messages/async_command_messages.py +507 -0
  126. autocoder/common/international/messages/auto_coder_messages.py +2208 -0
  127. autocoder/common/international/messages/chat_auto_coder_messages.py +1547 -0
  128. autocoder/common/international/messages/command_help_messages.py +986 -0
  129. autocoder/common/international/messages/conversation_command_messages.py +191 -0
  130. autocoder/common/international/messages/git_helper_plugin_messages.py +159 -0
  131. autocoder/common/international/messages/queue_command_messages.py +751 -0
  132. autocoder/common/international/messages/rules_command_messages.py +77 -0
  133. autocoder/common/international/messages/sdk_messages.py +1707 -0
  134. autocoder/common/international/messages/token_helper_plugin_messages.py +361 -0
  135. autocoder/common/international/messages/tool_display_messages.py +1212 -0
  136. autocoder/common/international/messages/workflow_exception_messages.py +473 -0
  137. autocoder/common/international/test_international.py +612 -0
  138. autocoder/common/linter_core/__init__.py +28 -0
  139. autocoder/common/linter_core/base_linter.py +61 -0
  140. autocoder/common/linter_core/config_loader.py +271 -0
  141. autocoder/common/linter_core/formatters/__init__.py +0 -0
  142. autocoder/common/linter_core/formatters/base_formatter.py +38 -0
  143. autocoder/common/linter_core/formatters/raw_formatter.py +17 -0
  144. autocoder/common/linter_core/linter.py +166 -0
  145. autocoder/common/linter_core/linter_factory.py +216 -0
  146. autocoder/common/linter_core/linter_manager.py +333 -0
  147. autocoder/common/linter_core/linters/__init__.py +9 -0
  148. autocoder/common/linter_core/linters/java_linter.py +342 -0
  149. autocoder/common/linter_core/linters/python_linter.py +115 -0
  150. autocoder/common/linter_core/linters/typescript_linter.py +119 -0
  151. autocoder/common/linter_core/models/__init__.py +7 -0
  152. autocoder/common/linter_core/models/lint_result.py +91 -0
  153. autocoder/common/linter_core/models.py +33 -0
  154. autocoder/common/linter_core/tests/__init__.py +3 -0
  155. autocoder/common/linter_core/tests/test_config_loader.py +323 -0
  156. autocoder/common/linter_core/tests/test_config_loading.py +308 -0
  157. autocoder/common/linter_core/tests/test_factory_manager.py +234 -0
  158. autocoder/common/linter_core/tests/test_formatters.py +147 -0
  159. autocoder/common/linter_core/tests/test_integration.py +317 -0
  160. autocoder/common/linter_core/tests/test_java_linter.py +496 -0
  161. autocoder/common/linter_core/tests/test_linters.py +265 -0
  162. autocoder/common/linter_core/tests/test_models.py +81 -0
  163. autocoder/common/linter_core/tests/verify_config_loading.py +296 -0
  164. autocoder/common/linter_core/tests/verify_fixes.py +183 -0
  165. autocoder/common/llm_friendly_package/__init__.py +31 -0
  166. autocoder/common/llm_friendly_package/base_manager.py +102 -0
  167. autocoder/common/llm_friendly_package/docs_manager.py +121 -0
  168. autocoder/common/llm_friendly_package/library_manager.py +171 -0
  169. autocoder/common/{llm_friendly_package.py → llm_friendly_package/main_manager.py} +204 -231
  170. autocoder/common/llm_friendly_package/models.py +40 -0
  171. autocoder/common/llm_friendly_package/test_llm_friendly_package.py +536 -0
  172. autocoder/common/llms/__init__.py +15 -0
  173. autocoder/common/llms/demo_error_handling.py +85 -0
  174. autocoder/common/llms/factory.py +142 -0
  175. autocoder/common/llms/manager.py +264 -0
  176. autocoder/common/llms/pricing.py +121 -0
  177. autocoder/common/llms/registry.py +316 -0
  178. autocoder/common/llms/schema.py +77 -0
  179. autocoder/common/llms/simple_demo.py +45 -0
  180. autocoder/common/llms/test_quick_model.py +116 -0
  181. autocoder/common/llms/test_remove_functionality.py +182 -0
  182. autocoder/common/llms/tests/__init__.py +1 -0
  183. autocoder/common/llms/tests/test_manager.py +330 -0
  184. autocoder/common/llms/tests/test_registry.py +364 -0
  185. autocoder/common/mcp_tools/__init__.py +62 -0
  186. autocoder/common/{mcp_tools.py → mcp_tools/executor.py} +49 -40
  187. autocoder/common/{mcp_hub.py → mcp_tools/hub.py} +42 -68
  188. autocoder/common/{mcp_server_install.py → mcp_tools/installer.py} +16 -28
  189. autocoder/common/{mcp_server.py → mcp_tools/server.py} +176 -48
  190. autocoder/common/mcp_tools/test_keyboard_interrupt.py +93 -0
  191. autocoder/common/mcp_tools/test_mcp_tools.py +391 -0
  192. autocoder/common/{mcp_server_types.py → mcp_tools/types.py} +121 -48
  193. autocoder/common/mcp_tools/verify_functionality.py +202 -0
  194. autocoder/common/model_speed_tester.py +32 -26
  195. autocoder/common/priority_directory_finder/__init__.py +142 -0
  196. autocoder/common/priority_directory_finder/examples.py +230 -0
  197. autocoder/common/priority_directory_finder/finder.py +283 -0
  198. autocoder/common/priority_directory_finder/models.py +236 -0
  199. autocoder/common/priority_directory_finder/test_priority_directory_finder.py +431 -0
  200. autocoder/common/project_scanner/__init__.py +18 -0
  201. autocoder/common/project_scanner/compat.py +77 -0
  202. autocoder/common/project_scanner/scanner.py +436 -0
  203. autocoder/common/project_tracker/__init__.py +27 -0
  204. autocoder/common/project_tracker/api.py +228 -0
  205. autocoder/common/project_tracker/demo.py +272 -0
  206. autocoder/common/project_tracker/tracker.py +487 -0
  207. autocoder/common/project_tracker/types.py +53 -0
  208. autocoder/common/pruner/__init__.py +67 -0
  209. autocoder/common/pruner/agentic_conversation_pruner.py +651 -102
  210. autocoder/common/pruner/conversation_message_ids_api.py +386 -0
  211. autocoder/common/pruner/conversation_message_ids_manager.py +347 -0
  212. autocoder/common/pruner/conversation_message_ids_pruner.py +473 -0
  213. autocoder/common/pruner/conversation_normalizer.py +347 -0
  214. autocoder/common/pruner/conversation_pruner.py +26 -6
  215. autocoder/common/pruner/test_agentic_conversation_pruner.py +554 -112
  216. autocoder/common/pruner/test_conversation_normalizer.py +502 -0
  217. autocoder/common/pruner/test_tool_content_detector.py +324 -0
  218. autocoder/common/pruner/tool_content_detector.py +227 -0
  219. autocoder/common/pruner/tools/__init__.py +18 -0
  220. autocoder/common/pruner/tools/query_message_ids.py +264 -0
  221. autocoder/common/pruner/tools/test_agentic_pruning_logic.py +432 -0
  222. autocoder/common/pruner/tools/test_message_ids_pruning_only.py +192 -0
  223. autocoder/common/pull_requests/__init__.py +9 -1
  224. autocoder/common/pull_requests/utils.py +122 -1
  225. autocoder/common/rag_manager/rag_manager.py +36 -40
  226. autocoder/common/rulefiles/__init__.py +53 -1
  227. autocoder/common/rulefiles/api.py +250 -0
  228. autocoder/common/rulefiles/core/__init__.py +14 -0
  229. autocoder/common/rulefiles/core/manager.py +241 -0
  230. autocoder/common/rulefiles/core/selector.py +805 -0
  231. autocoder/common/rulefiles/models/__init__.py +20 -0
  232. autocoder/common/rulefiles/models/index.py +16 -0
  233. autocoder/common/rulefiles/models/init_rule.py +18 -0
  234. autocoder/common/rulefiles/models/rule_file.py +18 -0
  235. autocoder/common/rulefiles/models/rule_relevance.py +14 -0
  236. autocoder/common/rulefiles/models/summary.py +16 -0
  237. autocoder/common/rulefiles/test_rulefiles.py +776 -0
  238. autocoder/common/rulefiles/utils/__init__.py +34 -0
  239. autocoder/common/rulefiles/utils/monitor.py +86 -0
  240. autocoder/common/rulefiles/utils/parser.py +230 -0
  241. autocoder/common/save_formatted_log.py +67 -10
  242. autocoder/common/search_replace.py +8 -1
  243. autocoder/common/search_replace_patch/__init__.py +24 -0
  244. autocoder/common/search_replace_patch/base.py +115 -0
  245. autocoder/common/search_replace_patch/manager.py +248 -0
  246. autocoder/common/search_replace_patch/patch_replacer.py +304 -0
  247. autocoder/common/search_replace_patch/similarity_replacer.py +306 -0
  248. autocoder/common/search_replace_patch/string_replacer.py +181 -0
  249. autocoder/common/search_replace_patch/tests/__init__.py +3 -0
  250. autocoder/common/search_replace_patch/tests/run_tests.py +126 -0
  251. autocoder/common/search_replace_patch/tests/test_base.py +188 -0
  252. autocoder/common/search_replace_patch/tests/test_empty_line_insert.py +233 -0
  253. autocoder/common/search_replace_patch/tests/test_integration.py +389 -0
  254. autocoder/common/search_replace_patch/tests/test_manager.py +351 -0
  255. autocoder/common/search_replace_patch/tests/test_patch_replacer.py +316 -0
  256. autocoder/common/search_replace_patch/tests/test_regex_replacer.py +306 -0
  257. autocoder/common/search_replace_patch/tests/test_similarity_replacer.py +384 -0
  258. autocoder/common/shell_commands/__init__.py +197 -0
  259. autocoder/common/shell_commands/background_process_notifier.py +346 -0
  260. autocoder/common/shell_commands/command_executor.py +1127 -0
  261. autocoder/common/shell_commands/error_recovery.py +541 -0
  262. autocoder/common/shell_commands/exceptions.py +120 -0
  263. autocoder/common/shell_commands/interactive_executor.py +476 -0
  264. autocoder/common/shell_commands/interactive_pexpect_process.py +623 -0
  265. autocoder/common/shell_commands/interactive_process.py +744 -0
  266. autocoder/common/shell_commands/interactive_session_manager.py +1014 -0
  267. autocoder/common/shell_commands/monitoring.py +529 -0
  268. autocoder/common/shell_commands/process_cleanup.py +386 -0
  269. autocoder/common/shell_commands/process_manager.py +606 -0
  270. autocoder/common/shell_commands/test_interactive_pexpect_process.py +281 -0
  271. autocoder/common/shell_commands/tests/__init__.py +6 -0
  272. autocoder/common/shell_commands/tests/conftest.py +118 -0
  273. autocoder/common/shell_commands/tests/test_background_process_notifier.py +703 -0
  274. autocoder/common/shell_commands/tests/test_command_executor.py +448 -0
  275. autocoder/common/shell_commands/tests/test_error_recovery.py +305 -0
  276. autocoder/common/shell_commands/tests/test_exceptions.py +299 -0
  277. autocoder/common/shell_commands/tests/test_execute_batch.py +588 -0
  278. autocoder/common/shell_commands/tests/test_indented_batch_commands.py +244 -0
  279. autocoder/common/shell_commands/tests/test_integration.py +664 -0
  280. autocoder/common/shell_commands/tests/test_monitoring.py +546 -0
  281. autocoder/common/shell_commands/tests/test_performance.py +632 -0
  282. autocoder/common/shell_commands/tests/test_process_cleanup.py +397 -0
  283. autocoder/common/shell_commands/tests/test_process_manager.py +606 -0
  284. autocoder/common/shell_commands/tests/test_timeout_config.py +343 -0
  285. autocoder/common/shell_commands/tests/test_timeout_manager.py +520 -0
  286. autocoder/common/shell_commands/timeout_config.py +315 -0
  287. autocoder/common/shell_commands/timeout_manager.py +352 -0
  288. autocoder/common/terminal_paste/__init__.py +14 -0
  289. autocoder/common/terminal_paste/demo.py +145 -0
  290. autocoder/common/terminal_paste/demo_paste_functionality.py +95 -0
  291. autocoder/common/terminal_paste/paste_handler.py +200 -0
  292. autocoder/common/terminal_paste/paste_manager.py +118 -0
  293. autocoder/common/terminal_paste/tests/__init__.py +1 -0
  294. autocoder/common/terminal_paste/tests/test_paste_handler.py +182 -0
  295. autocoder/common/terminal_paste/tests/test_paste_manager.py +126 -0
  296. autocoder/common/terminal_paste/utils.py +163 -0
  297. autocoder/common/test_autocoder_args.py +232 -0
  298. autocoder/common/test_env_manager.py +173 -0
  299. autocoder/common/test_env_manager_integration.py +159 -0
  300. autocoder/common/text_similarity/__init__.py +9 -0
  301. autocoder/common/text_similarity/demo.py +216 -0
  302. autocoder/common/text_similarity/examples.py +266 -0
  303. autocoder/common/text_similarity/test_text_similarity.py +306 -0
  304. autocoder/common/text_similarity/text_similarity.py +194 -0
  305. autocoder/common/text_similarity/utils.py +125 -0
  306. autocoder/common/todos/__init__.py +61 -0
  307. autocoder/common/todos/cache/__init__.py +16 -0
  308. autocoder/common/todos/cache/base_cache.py +89 -0
  309. autocoder/common/todos/cache/cache_manager.py +228 -0
  310. autocoder/common/todos/cache/memory_cache.py +225 -0
  311. autocoder/common/todos/config.py +155 -0
  312. autocoder/common/todos/exceptions.py +35 -0
  313. autocoder/common/todos/get_todo_manager.py +161 -0
  314. autocoder/common/todos/manager.py +537 -0
  315. autocoder/common/todos/models.py +239 -0
  316. autocoder/common/todos/storage/__init__.py +14 -0
  317. autocoder/common/todos/storage/base_storage.py +76 -0
  318. autocoder/common/todos/storage/file_storage.py +278 -0
  319. autocoder/common/tokens/counter.py +24 -2
  320. autocoder/common/tools_manager/__init__.py +17 -0
  321. autocoder/common/tools_manager/examples.py +162 -0
  322. autocoder/common/tools_manager/manager.py +385 -0
  323. autocoder/common/tools_manager/models.py +39 -0
  324. autocoder/common/tools_manager/test_tools_manager.py +303 -0
  325. autocoder/common/tools_manager/utils.py +191 -0
  326. autocoder/common/v2/agent/agentic_callbacks.py +270 -0
  327. autocoder/common/v2/agent/agentic_edit.py +2699 -1856
  328. autocoder/common/v2/agent/agentic_edit_change_manager.py +474 -0
  329. autocoder/common/v2/agent/agentic_edit_tools/__init__.py +35 -1
  330. autocoder/common/v2/agent/agentic_edit_tools/ac_mod_list_tool_resolver.py +279 -0
  331. autocoder/common/v2/agent/agentic_edit_tools/ac_mod_write_tool_resolver.py +10 -1
  332. autocoder/common/v2/agent/agentic_edit_tools/background_task_tool_resolver.py +1167 -0
  333. autocoder/common/v2/agent/agentic_edit_tools/base_tool_resolver.py +2 -2
  334. autocoder/common/v2/agent/agentic_edit_tools/conversation_message_ids_read_tool_resolver.py +214 -0
  335. autocoder/common/v2/agent/agentic_edit_tools/conversation_message_ids_write_tool_resolver.py +299 -0
  336. autocoder/common/v2/agent/agentic_edit_tools/count_tokens_tool_resolver.py +290 -0
  337. autocoder/common/v2/agent/agentic_edit_tools/execute_command_tool_resolver.py +564 -29
  338. autocoder/common/v2/agent/agentic_edit_tools/execute_workflow_tool_resolver.py +485 -0
  339. autocoder/common/v2/agent/agentic_edit_tools/extract_to_text_tool_resolver.py +225 -0
  340. autocoder/common/v2/agent/agentic_edit_tools/lint_report.py +79 -0
  341. autocoder/common/v2/agent/agentic_edit_tools/linter_config_models.py +343 -0
  342. autocoder/common/v2/agent/agentic_edit_tools/linter_enabled_tool_resolver.py +189 -0
  343. autocoder/common/v2/agent/agentic_edit_tools/list_files_tool_resolver.py +169 -101
  344. autocoder/common/v2/agent/agentic_edit_tools/load_extra_document_tool_resolver.py +356 -0
  345. autocoder/common/v2/agent/agentic_edit_tools/read_file_tool_resolver.py +243 -50
  346. autocoder/common/v2/agent/agentic_edit_tools/replace_in_file_tool_resolver.py +667 -147
  347. autocoder/common/v2/agent/agentic_edit_tools/run_named_subagents_tool_resolver.py +691 -0
  348. autocoder/common/v2/agent/agentic_edit_tools/search_files_tool_resolver.py +410 -86
  349. autocoder/common/v2/agent/agentic_edit_tools/session_interactive_tool_resolver.py +115 -0
  350. autocoder/common/v2/agent/agentic_edit_tools/session_start_tool_resolver.py +190 -0
  351. autocoder/common/v2/agent/agentic_edit_tools/session_stop_tool_resolver.py +76 -0
  352. autocoder/common/v2/agent/agentic_edit_tools/test_write_to_file_tool_resolver.py +207 -192
  353. autocoder/common/v2/agent/agentic_edit_tools/todo_read_tool_resolver.py +80 -63
  354. autocoder/common/v2/agent/agentic_edit_tools/todo_write_tool_resolver.py +237 -233
  355. autocoder/common/v2/agent/agentic_edit_tools/use_mcp_tool_resolver.py +2 -2
  356. autocoder/common/v2/agent/agentic_edit_tools/web_crawl_tool_resolver.py +557 -0
  357. autocoder/common/v2/agent/agentic_edit_tools/web_search_tool_resolver.py +600 -0
  358. autocoder/common/v2/agent/agentic_edit_tools/write_to_file_tool_resolver.py +56 -121
  359. autocoder/common/v2/agent/agentic_edit_types.py +343 -9
  360. autocoder/common/v2/agent/runner/__init__.py +3 -3
  361. autocoder/common/v2/agent/runner/base_runner.py +12 -26
  362. autocoder/common/v2/agent/runner/{event_runner.py → file_based_event_runner.py} +3 -2
  363. autocoder/common/v2/agent/runner/sdk_runner.py +150 -8
  364. autocoder/common/v2/agent/runner/terminal_runner.py +170 -57
  365. autocoder/common/v2/agent/runner/tool_display.py +557 -159
  366. autocoder/common/v2/agent/test_agentic_callbacks.py +265 -0
  367. autocoder/common/v2/agent/test_agentic_edit.py +194 -0
  368. autocoder/common/v2/agent/tool_caller/__init__.py +24 -0
  369. autocoder/common/v2/agent/tool_caller/default_tool_resolver_map.py +135 -0
  370. autocoder/common/v2/agent/tool_caller/integration_test.py +172 -0
  371. autocoder/common/v2/agent/tool_caller/plugins/__init__.py +14 -0
  372. autocoder/common/v2/agent/tool_caller/plugins/base_plugin.py +126 -0
  373. autocoder/common/v2/agent/tool_caller/plugins/examples/__init__.py +13 -0
  374. autocoder/common/v2/agent/tool_caller/plugins/examples/logging_plugin.py +164 -0
  375. autocoder/common/v2/agent/tool_caller/plugins/examples/security_filter_plugin.py +198 -0
  376. autocoder/common/v2/agent/tool_caller/plugins/plugin_interface.py +141 -0
  377. autocoder/common/v2/agent/tool_caller/test_tool_caller.py +278 -0
  378. autocoder/common/v2/agent/tool_caller/tool_call_plugin_manager.py +331 -0
  379. autocoder/common/v2/agent/tool_caller/tool_caller.py +337 -0
  380. autocoder/common/v2/agent/tool_caller/usage_example.py +193 -0
  381. autocoder/common/v2/code_agentic_editblock_manager.py +4 -4
  382. autocoder/common/v2/code_auto_generate.py +136 -78
  383. autocoder/common/v2/code_auto_generate_diff.py +135 -79
  384. autocoder/common/v2/code_auto_generate_editblock.py +174 -99
  385. autocoder/common/v2/code_auto_generate_strict_diff.py +151 -71
  386. autocoder/common/v2/code_auto_merge.py +1 -1
  387. autocoder/common/v2/code_auto_merge_editblock.py +13 -1
  388. autocoder/common/v2/code_diff_manager.py +3 -3
  389. autocoder/common/v2/code_editblock_manager.py +4 -14
  390. autocoder/common/v2/code_manager.py +1 -1
  391. autocoder/common/v2/code_strict_diff_manager.py +2 -2
  392. autocoder/common/wrap_llm_hint/__init__.py +10 -0
  393. autocoder/common/wrap_llm_hint/test_wrap_llm_hint.py +1067 -0
  394. autocoder/common/wrap_llm_hint/utils.py +432 -0
  395. autocoder/common/wrap_llm_hint/wrap_llm_hint.py +323 -0
  396. autocoder/completer/__init__.py +8 -0
  397. autocoder/completer/command_completer_v2.py +1094 -0
  398. autocoder/default_project/__init__.py +501 -0
  399. autocoder/dispacher/__init__.py +4 -12
  400. autocoder/dispacher/actions/action.py +400 -129
  401. autocoder/dispacher/actions/plugins/action_regex_project.py +2 -2
  402. autocoder/index/entry.py +117 -125
  403. autocoder/{agent → index/filter}/agentic_filter.py +322 -333
  404. autocoder/index/filter/normal_filter.py +5 -11
  405. autocoder/index/filter/quick_filter.py +1 -1
  406. autocoder/index/index.py +36 -9
  407. autocoder/index/tests/__init__.py +1 -0
  408. autocoder/index/tests/run_tests.py +195 -0
  409. autocoder/index/tests/test_entry.py +303 -0
  410. autocoder/index/tests/test_index_manager.py +314 -0
  411. autocoder/index/tests/test_module_integration.py +300 -0
  412. autocoder/index/tests/test_symbols_utils.py +183 -0
  413. autocoder/inner/__init__.py +4 -0
  414. autocoder/inner/agentic.py +923 -0
  415. autocoder/inner/async_command_handler.py +992 -0
  416. autocoder/inner/conversation_command_handlers.py +623 -0
  417. autocoder/inner/merge_command_handler.py +213 -0
  418. autocoder/inner/queue_command_handler.py +684 -0
  419. autocoder/models.py +95 -266
  420. autocoder/plugins/git_helper_plugin.py +31 -29
  421. autocoder/plugins/token_helper_plugin.py +65 -46
  422. autocoder/pyproject/__init__.py +32 -29
  423. autocoder/rag/agentic_rag.py +215 -75
  424. autocoder/rag/cache/simple_cache.py +1 -2
  425. autocoder/rag/loaders/image_loader.py +1 -1
  426. autocoder/rag/long_context_rag.py +42 -26
  427. autocoder/rag/qa_conversation_strategy.py +1 -1
  428. autocoder/rag/terminal/__init__.py +17 -0
  429. autocoder/rag/terminal/args.py +581 -0
  430. autocoder/rag/terminal/bootstrap.py +61 -0
  431. autocoder/rag/terminal/command_handlers.py +653 -0
  432. autocoder/rag/terminal/formatters/__init__.py +20 -0
  433. autocoder/rag/terminal/formatters/base.py +70 -0
  434. autocoder/rag/terminal/formatters/json_format.py +66 -0
  435. autocoder/rag/terminal/formatters/stream_json.py +95 -0
  436. autocoder/rag/terminal/formatters/text.py +28 -0
  437. autocoder/rag/terminal/init.py +120 -0
  438. autocoder/rag/terminal/utils.py +106 -0
  439. autocoder/rag/test_agentic_rag.py +389 -0
  440. autocoder/rag/test_doc_filter.py +3 -3
  441. autocoder/rag/test_long_context_rag.py +1 -1
  442. autocoder/rag/test_token_limiter.py +517 -10
  443. autocoder/rag/token_counter.py +3 -0
  444. autocoder/rag/token_limiter.py +19 -15
  445. autocoder/rag/tools/__init__.py +26 -2
  446. autocoder/rag/tools/bochaai_example.py +343 -0
  447. autocoder/rag/tools/bochaai_sdk.py +541 -0
  448. autocoder/rag/tools/metaso_example.py +268 -0
  449. autocoder/rag/tools/metaso_sdk.py +417 -0
  450. autocoder/rag/tools/recall_tool.py +28 -7
  451. autocoder/rag/tools/run_integration_tests.py +204 -0
  452. autocoder/rag/tools/test_all_providers.py +318 -0
  453. autocoder/rag/tools/test_bochaai_integration.py +482 -0
  454. autocoder/rag/tools/test_final_integration.py +215 -0
  455. autocoder/rag/tools/test_metaso_integration.py +424 -0
  456. autocoder/rag/tools/test_metaso_real.py +171 -0
  457. autocoder/rag/tools/test_web_crawl_tool.py +639 -0
  458. autocoder/rag/tools/test_web_search_tool.py +509 -0
  459. autocoder/rag/tools/todo_read_tool.py +202 -0
  460. autocoder/rag/tools/todo_write_tool.py +412 -0
  461. autocoder/rag/tools/web_crawl_tool.py +634 -0
  462. autocoder/rag/tools/web_search_tool.py +558 -0
  463. autocoder/rag/tools/web_tools_example.py +119 -0
  464. autocoder/rag/types.py +16 -0
  465. autocoder/rag/variable_holder.py +4 -2
  466. autocoder/rags.py +86 -79
  467. autocoder/regexproject/__init__.py +23 -21
  468. autocoder/sdk/__init__.py +46 -190
  469. autocoder/sdk/api.py +370 -0
  470. autocoder/sdk/async_runner/__init__.py +26 -0
  471. autocoder/sdk/async_runner/async_executor.py +650 -0
  472. autocoder/sdk/async_runner/async_handler.py +356 -0
  473. autocoder/sdk/async_runner/markdown_processor.py +595 -0
  474. autocoder/sdk/async_runner/task_metadata.py +284 -0
  475. autocoder/sdk/async_runner/worktree_manager.py +438 -0
  476. autocoder/sdk/cli/__init__.py +2 -5
  477. autocoder/sdk/cli/formatters.py +28 -204
  478. autocoder/sdk/cli/handlers.py +77 -44
  479. autocoder/sdk/cli/main.py +154 -171
  480. autocoder/sdk/cli/options.py +95 -22
  481. autocoder/sdk/constants.py +139 -51
  482. autocoder/sdk/core/auto_coder_core.py +484 -109
  483. autocoder/sdk/core/bridge.py +297 -115
  484. autocoder/sdk/exceptions.py +18 -12
  485. autocoder/sdk/formatters/__init__.py +19 -0
  486. autocoder/sdk/formatters/input.py +64 -0
  487. autocoder/sdk/formatters/output.py +247 -0
  488. autocoder/sdk/formatters/stream.py +54 -0
  489. autocoder/sdk/models/__init__.py +6 -5
  490. autocoder/sdk/models/options.py +55 -18
  491. autocoder/sdk/utils/formatters.py +27 -195
  492. autocoder/suffixproject/__init__.py +28 -25
  493. autocoder/terminal/__init__.py +14 -0
  494. autocoder/terminal/app.py +454 -0
  495. autocoder/terminal/args.py +32 -0
  496. autocoder/terminal/bootstrap.py +178 -0
  497. autocoder/terminal/command_processor.py +521 -0
  498. autocoder/terminal/command_registry.py +57 -0
  499. autocoder/terminal/help.py +97 -0
  500. autocoder/terminal/tasks/__init__.py +5 -0
  501. autocoder/terminal/tasks/background.py +77 -0
  502. autocoder/terminal/tasks/task_event.py +70 -0
  503. autocoder/terminal/ui/__init__.py +13 -0
  504. autocoder/terminal/ui/completer.py +268 -0
  505. autocoder/terminal/ui/keybindings.py +75 -0
  506. autocoder/terminal/ui/session.py +41 -0
  507. autocoder/terminal/ui/toolbar.py +64 -0
  508. autocoder/terminal/utils/__init__.py +13 -0
  509. autocoder/terminal/utils/errors.py +18 -0
  510. autocoder/terminal/utils/paths.py +19 -0
  511. autocoder/terminal/utils/shell.py +43 -0
  512. autocoder/terminal_v3/__init__.py +10 -0
  513. autocoder/terminal_v3/app.py +201 -0
  514. autocoder/terminal_v3/handlers/__init__.py +5 -0
  515. autocoder/terminal_v3/handlers/command_handler.py +131 -0
  516. autocoder/terminal_v3/models/__init__.py +6 -0
  517. autocoder/terminal_v3/models/conversation_buffer.py +214 -0
  518. autocoder/terminal_v3/models/message.py +50 -0
  519. autocoder/terminal_v3/models/tool_display.py +247 -0
  520. autocoder/terminal_v3/ui/__init__.py +7 -0
  521. autocoder/terminal_v3/ui/keybindings.py +56 -0
  522. autocoder/terminal_v3/ui/layout.py +141 -0
  523. autocoder/terminal_v3/ui/styles.py +43 -0
  524. autocoder/tsproject/__init__.py +23 -23
  525. autocoder/utils/auto_coder_utils/chat_stream_out.py +1 -1
  526. autocoder/utils/llms.py +88 -80
  527. autocoder/utils/math_utils.py +101 -0
  528. autocoder/utils/model_provider_selector.py +16 -4
  529. autocoder/utils/operate_config_api.py +33 -5
  530. autocoder/utils/thread_utils.py +2 -2
  531. autocoder/version.py +4 -2
  532. autocoder/workflow_agents/__init__.py +84 -0
  533. autocoder/workflow_agents/agent.py +143 -0
  534. autocoder/workflow_agents/exceptions.py +573 -0
  535. autocoder/workflow_agents/executor.py +665 -0
  536. autocoder/workflow_agents/loader.py +749 -0
  537. autocoder/workflow_agents/runner.py +267 -0
  538. autocoder/workflow_agents/types.py +173 -0
  539. autocoder/workflow_agents/utils.py +434 -0
  540. autocoder/workflow_agents/workflow_manager.py +211 -0
  541. auto_coder-1.0.0.dist-info/METADATA +0 -396
  542. auto_coder-1.0.0.dist-info/RECORD +0 -442
  543. auto_coder-1.0.0.dist-info/licenses/LICENSE +0 -201
  544. autocoder/auto_coder_server.py +0 -672
  545. autocoder/benchmark.py +0 -138
  546. autocoder/common/ac_style_command_parser/example.py +0 -7
  547. autocoder/common/cleaner.py +0 -31
  548. autocoder/common/command_completer_v2.py +0 -615
  549. autocoder/common/context_pruner.py +0 -477
  550. autocoder/common/conversation_pruner.py +0 -132
  551. autocoder/common/directory_cache/__init__.py +0 -1
  552. autocoder/common/directory_cache/cache.py +0 -192
  553. autocoder/common/directory_cache/test_cache.py +0 -190
  554. autocoder/common/file_checkpoint/examples.py +0 -217
  555. autocoder/common/llm_friendly_package_example.py +0 -138
  556. autocoder/common/llm_friendly_package_test.py +0 -63
  557. autocoder/common/pull_requests/test_module.py +0 -1
  558. autocoder/common/rulefiles/autocoderrules_utils.py +0 -484
  559. autocoder/common/text.py +0 -30
  560. autocoder/common/v2/agent/agentic_edit_tools/list_package_info_tool_resolver.py +0 -42
  561. autocoder/common/v2/agent/agentic_edit_tools/test_execute_command_tool_resolver.py +0 -70
  562. autocoder/common/v2/agent/agentic_edit_tools/test_search_files_tool_resolver.py +0 -163
  563. autocoder/common/v2/agent/agentic_tool_display.py +0 -183
  564. autocoder/plugins/dynamic_completion_example.py +0 -148
  565. autocoder/plugins/sample_plugin.py +0 -160
  566. autocoder/sdk/cli/__main__.py +0 -26
  567. autocoder/sdk/cli/completion_wrapper.py +0 -38
  568. autocoder/sdk/cli/install_completion.py +0 -301
  569. autocoder/sdk/models/messages.py +0 -209
  570. autocoder/sdk/session/__init__.py +0 -32
  571. autocoder/sdk/session/session.py +0 -106
  572. autocoder/sdk/session/session_manager.py +0 -56
  573. {auto_coder-1.0.0.dist-info → auto_coder-2.0.1.dist-info}/top_level.txt +0 -0
  574. /autocoder/{sdk/example.py → common/agent_query_queue/__init__.py} +0 -0
@@ -0,0 +1,509 @@
1
+ """
2
+ WebSearchTool 的 pytest 测试类
3
+
4
+ 该测试模块使用纯 pytest 风格,包含 fixtures、参数化测试和覆盖率测试。
5
+ """
6
+
7
+ import pytest
8
+ import os
9
+ from unittest.mock import Mock, patch, MagicMock
10
+ from typing import Dict, Any, List
11
+
12
+ from autocoder.agent.base_agentic.types import ToolResult
13
+ from .web_search_tool import WebSearchTool, WebSearchToolResolver, register_web_search_tool
14
+
15
+
16
+ class TestWebSearchTool:
17
+ """WebSearchTool 基础功能测试"""
18
+
19
+ def test_web_search_tool_creation(self):
20
+ """测试 WebSearchTool 实例创建"""
21
+ tool = WebSearchTool(query="test query")
22
+ assert tool.query == "test query"
23
+ assert tool.limit == 5 # 默认值
24
+ assert tool.sources is None
25
+ assert tool.scrape_options is None
26
+ assert tool.location is None
27
+ assert tool.tbs is None
28
+
29
+ def test_web_search_tool_with_all_params(self):
30
+ """测试 WebSearchTool 使用所有参数创建"""
31
+ tool = WebSearchTool(
32
+ query="Python tutorial",
33
+ limit=10,
34
+ sources=["web", "news"],
35
+ scrape_options={"formats": ["markdown"]},
36
+ location="China",
37
+ tbs="qdr:d"
38
+ )
39
+ assert tool.query == "Python tutorial"
40
+ assert tool.limit == 10
41
+ assert tool.sources == ["web", "news"]
42
+ assert tool.scrape_options == {"formats": ["markdown"]}
43
+ assert tool.location == "China"
44
+ assert tool.tbs == "qdr:d"
45
+
46
+
47
+ class TestWebSearchToolResolver:
48
+ """WebSearchToolResolver 功能测试"""
49
+
50
+ @pytest.fixture
51
+ def mock_agent(self):
52
+ """创建 mock agent"""
53
+ agent = Mock()
54
+ agent.rag = Mock()
55
+ return agent
56
+
57
+ @pytest.fixture
58
+ def mock_args_without_api_key(self):
59
+ """创建没有 API key 的 mock args"""
60
+ args = Mock()
61
+ args.firecrawl_api_key = None
62
+ return args
63
+
64
+ @pytest.fixture
65
+ def mock_args_with_api_key(self):
66
+ """创建有 API key 的 mock args"""
67
+ args = Mock()
68
+ args.firecrawl_api_key = "test-api-key"
69
+ return args
70
+
71
+ @pytest.fixture
72
+ def basic_search_tool(self):
73
+ """创建基础搜索工具"""
74
+ return WebSearchTool(query="test query")
75
+
76
+ @pytest.fixture
77
+ def advanced_search_tool(self):
78
+ """创建高级搜索工具"""
79
+ return WebSearchTool(
80
+ query="Python RAG",
81
+ limit=3,
82
+ sources=["web"],
83
+ location="US"
84
+ )
85
+
86
+ def test_resolver_creation(self, mock_agent, basic_search_tool, mock_args_without_api_key):
87
+ """测试解析器创建"""
88
+ resolver = WebSearchToolResolver(mock_agent, basic_search_tool, mock_args_without_api_key)
89
+ assert resolver.agent == mock_agent
90
+ assert resolver.tool == basic_search_tool
91
+ assert resolver.args == mock_args_without_api_key
92
+
93
+ def test_resolve_without_api_key_in_args(self, mock_agent, basic_search_tool, mock_args_without_api_key):
94
+ """测试没有 API key 时的错误处理"""
95
+ resolver = WebSearchToolResolver(mock_agent, basic_search_tool, mock_args_without_api_key)
96
+
97
+ with patch.dict(os.environ, {}, clear=True):
98
+ result = resolver.resolve()
99
+
100
+ assert isinstance(result, ToolResult)
101
+ assert not result.success
102
+ assert "未提供 Firecrawl API key" in result.message
103
+ assert result.content == []
104
+
105
+ def test_resolve_with_api_key_from_env(self, mock_agent, basic_search_tool, mock_args_without_api_key):
106
+ """测试从环境变量获取 API key"""
107
+ resolver = WebSearchToolResolver(mock_agent, basic_search_tool, mock_args_without_api_key)
108
+
109
+ with patch.dict(os.environ, {'FIRECRAWL_API_KEY': 'env-api-key'}):
110
+ with patch('autocoder.rag.tools.web_search_tool.Firecrawl') as mock_firecrawl_class:
111
+ mock_firecrawl = Mock()
112
+ mock_firecrawl_class.return_value = mock_firecrawl
113
+ mock_firecrawl.search.return_value = {
114
+ 'success': True,
115
+ 'data': {
116
+ 'web': [
117
+ {
118
+ 'title': 'Test Result',
119
+ 'url': 'https://example.com',
120
+ 'description': 'Test description',
121
+ 'position': 1
122
+ }
123
+ ]
124
+ }
125
+ }
126
+
127
+ result = resolver.resolve()
128
+
129
+ assert isinstance(result, ToolResult)
130
+ assert result.success
131
+ mock_firecrawl_class.assert_called_once_with(api_key='env-api-key')
132
+ mock_firecrawl.search.assert_called_once()
133
+
134
+ def test_resolve_without_firecrawl_sdk(self, mock_agent, basic_search_tool, mock_args_with_api_key):
135
+ """测试没有安装 Firecrawl SDK 时的错误处理"""
136
+ resolver = WebSearchToolResolver(mock_agent, basic_search_tool, mock_args_with_api_key)
137
+
138
+ with patch('autocoder.rag.tools.web_search_tool.Firecrawl', side_effect=ImportError):
139
+ result = resolver.resolve()
140
+
141
+ assert isinstance(result, ToolResult)
142
+ assert not result.success
143
+ assert "未安装 Firecrawl SDK" in result.message
144
+ assert "pip install firecrawl-py" in result.message
145
+
146
+ def test_resolve_successful_web_search(self, mock_agent, basic_search_tool, mock_args_with_api_key):
147
+ """测试成功的网页搜索"""
148
+ resolver = WebSearchToolResolver(mock_agent, basic_search_tool, mock_args_with_api_key)
149
+
150
+ mock_response = {
151
+ 'success': True,
152
+ 'data': {
153
+ 'web': [
154
+ {
155
+ 'title': 'Python Tutorial',
156
+ 'url': 'https://python.org/tutorial',
157
+ 'description': 'Official Python tutorial',
158
+ 'position': 1,
159
+ 'markdown': '# Python Tutorial\nLearn Python...',
160
+ 'links': ['https://python.org/docs'],
161
+ 'metadata': {'status': 200}
162
+ },
163
+ {
164
+ 'title': 'Advanced Python',
165
+ 'url': 'https://realpython.com',
166
+ 'description': 'Advanced Python concepts',
167
+ 'position': 2
168
+ }
169
+ ]
170
+ }
171
+ }
172
+
173
+ with patch('autocoder.rag.tools.web_search_tool.Firecrawl') as mock_firecrawl_class:
174
+ mock_firecrawl = Mock()
175
+ mock_firecrawl_class.return_value = mock_firecrawl
176
+ mock_firecrawl.search.return_value = mock_response
177
+
178
+ result = resolver.resolve()
179
+
180
+ assert isinstance(result, ToolResult)
181
+ assert result.success
182
+ assert "成功搜索到 2 个结果" in result.message
183
+ assert len(result.content) == 2
184
+
185
+ # 检查第一个结果
186
+ first_result = result.content[0]
187
+ assert first_result['type'] == 'web'
188
+ assert first_result['title'] == 'Python Tutorial'
189
+ assert first_result['url'] == 'https://python.org/tutorial'
190
+ assert first_result['description'] == 'Official Python tutorial'
191
+ assert first_result['position'] == 1
192
+ assert first_result['content'] == '# Python Tutorial\nLearn Python...'
193
+ assert first_result['links'] == ['https://python.org/docs']
194
+ assert first_result['metadata'] == {'status': 200}
195
+
196
+ # 检查第二个结果
197
+ second_result = result.content[1]
198
+ assert second_result['type'] == 'web'
199
+ assert second_result['title'] == 'Advanced Python'
200
+ assert 'content' not in second_result # 没有 markdown 内容
201
+
202
+ def test_resolve_successful_news_search(self, mock_agent, mock_args_with_api_key):
203
+ """测试成功的新闻搜索"""
204
+ news_tool = WebSearchTool(query="AI news", sources=["news"])
205
+ resolver = WebSearchToolResolver(mock_agent, news_tool, mock_args_with_api_key)
206
+
207
+ mock_response = {
208
+ 'success': True,
209
+ 'data': {
210
+ 'news': [
211
+ {
212
+ 'title': 'AI Breakthrough',
213
+ 'url': 'https://news.com/ai',
214
+ 'snippet': 'Latest AI developments...',
215
+ 'date': '2024-01-01',
216
+ 'position': 1
217
+ }
218
+ ]
219
+ }
220
+ }
221
+
222
+ with patch('autocoder.rag.tools.web_search_tool.Firecrawl') as mock_firecrawl_class:
223
+ mock_firecrawl = Mock()
224
+ mock_firecrawl_class.return_value = mock_firecrawl
225
+ mock_firecrawl.search.return_value = mock_response
226
+
227
+ result = resolver.resolve()
228
+
229
+ assert result.success
230
+ assert len(result.content) == 1
231
+ news_result = result.content[0]
232
+ assert news_result['type'] == 'news'
233
+ assert news_result['title'] == 'AI Breakthrough'
234
+ assert news_result['snippet'] == 'Latest AI developments...'
235
+ assert news_result['date'] == '2024-01-01'
236
+
237
+ def test_resolve_successful_image_search(self, mock_agent, mock_args_with_api_key):
238
+ """测试成功的图片搜索"""
239
+ image_tool = WebSearchTool(query="machine learning", sources=["images"])
240
+ resolver = WebSearchToolResolver(mock_agent, image_tool, mock_args_with_api_key)
241
+
242
+ mock_response = {
243
+ 'success': True,
244
+ 'data': {
245
+ 'images': [
246
+ {
247
+ 'title': 'ML Diagram',
248
+ 'imageUrl': 'https://example.com/ml.jpg',
249
+ 'url': 'https://example.com',
250
+ 'imageWidth': 1920,
251
+ 'imageHeight': 1080,
252
+ 'position': 1
253
+ }
254
+ ]
255
+ }
256
+ }
257
+
258
+ with patch('autocoder.rag.tools.web_search_tool.Firecrawl') as mock_firecrawl_class:
259
+ mock_firecrawl = Mock()
260
+ mock_firecrawl_class.return_value = mock_firecrawl
261
+ mock_firecrawl.search.return_value = mock_response
262
+
263
+ result = resolver.resolve()
264
+
265
+ assert result.success
266
+ assert len(result.content) == 1
267
+ image_result = result.content[0]
268
+ assert image_result['type'] == 'image'
269
+ assert image_result['title'] == 'ML Diagram'
270
+ assert image_result['imageUrl'] == 'https://example.com/ml.jpg'
271
+ assert image_result['imageWidth'] == 1920
272
+ assert image_result['imageHeight'] == 1080
273
+
274
+ def test_resolve_api_failure(self, mock_agent, basic_search_tool, mock_args_with_api_key):
275
+ """测试 API 调用失败"""
276
+ resolver = WebSearchToolResolver(mock_agent, basic_search_tool, mock_args_with_api_key)
277
+
278
+ mock_response = {
279
+ 'success': False,
280
+ 'error': 'API rate limit exceeded'
281
+ }
282
+
283
+ with patch('autocoder.rag.tools.web_search_tool.Firecrawl') as mock_firecrawl_class:
284
+ mock_firecrawl = Mock()
285
+ mock_firecrawl_class.return_value = mock_firecrawl
286
+ mock_firecrawl.search.return_value = mock_response
287
+
288
+ result = resolver.resolve()
289
+
290
+ assert not result.success
291
+ assert "搜索失败: API rate limit exceeded" in result.message
292
+
293
+ def test_resolve_with_advanced_params(self, mock_agent, advanced_search_tool, mock_args_with_api_key):
294
+ """测试使用高级参数的搜索"""
295
+ resolver = WebSearchToolResolver(mock_agent, advanced_search_tool, mock_args_with_api_key)
296
+
297
+ with patch('autocoder.rag.tools.web_search_tool.Firecrawl') as mock_firecrawl_class:
298
+ mock_firecrawl = Mock()
299
+ mock_firecrawl_class.return_value = mock_firecrawl
300
+ mock_firecrawl.search.return_value = {'success': True, 'data': {'web': []}}
301
+
302
+ result = resolver.resolve()
303
+
304
+ # 验证调用参数
305
+ call_args = mock_firecrawl.search.call_args[1]
306
+ assert call_args['query'] == "Python RAG"
307
+ assert call_args['limit'] == 3
308
+ assert call_args['sources'] == ["web"]
309
+ assert call_args['location'] == "US"
310
+
311
+ def test_resolve_exception_handling(self, mock_agent, basic_search_tool, mock_args_with_api_key):
312
+ """测试异常处理"""
313
+ resolver = WebSearchToolResolver(mock_agent, basic_search_tool, mock_args_with_api_key)
314
+
315
+ with patch('autocoder.rag.tools.web_search_tool.Firecrawl') as mock_firecrawl_class:
316
+ mock_firecrawl = Mock()
317
+ mock_firecrawl_class.return_value = mock_firecrawl
318
+ mock_firecrawl.search.side_effect = Exception("Network error")
319
+
320
+ result = resolver.resolve()
321
+
322
+ assert not result.success
323
+ assert "网页搜索工具执行失败" in result.message
324
+ assert "Network error" in result.message
325
+
326
+ @pytest.mark.parametrize("sources,expected_count", [
327
+ (["web"], 1),
328
+ (["news"], 1),
329
+ (["images"], 1),
330
+ (["web", "news"], 2),
331
+ (["web", "news", "images"], 3)
332
+ ])
333
+ def test_resolve_multiple_sources(self, mock_agent, mock_args_with_api_key, sources, expected_count):
334
+ """参数化测试:多种数据源组合"""
335
+ tool = WebSearchTool(query="test", sources=sources)
336
+ resolver = WebSearchToolResolver(mock_agent, tool, mock_args_with_api_key)
337
+
338
+ mock_data = {}
339
+ if "web" in sources:
340
+ mock_data["web"] = [{"title": "Web Result", "url": "http://web.com", "description": "desc", "position": 1}]
341
+ if "news" in sources:
342
+ mock_data["news"] = [{"title": "News Result", "url": "http://news.com", "snippet": "snippet", "date": "2024-01-01", "position": 1}]
343
+ if "images" in sources:
344
+ mock_data["images"] = [{"title": "Image Result", "imageUrl": "http://img.com/img.jpg", "url": "http://src.com", "imageWidth": 100, "imageHeight": 100, "position": 1}]
345
+
346
+ mock_response = {"success": True, "data": mock_data}
347
+
348
+ with patch('autocoder.rag.tools.web_search_tool.Firecrawl') as mock_firecrawl_class:
349
+ mock_firecrawl = Mock()
350
+ mock_firecrawl_class.return_value = mock_firecrawl
351
+ mock_firecrawl.search.return_value = mock_response
352
+
353
+ result = resolver.resolve()
354
+
355
+ assert result.success
356
+ assert len(result.content) == expected_count
357
+
358
+
359
+ class TestWebSearchToolIntegration:
360
+ """WebSearchTool 集成测试 - 实际调用 Firecrawl API"""
361
+
362
+ @pytest.fixture
363
+ def real_api_key(self):
364
+ """获取真实的 API key"""
365
+ api_key = os.getenv('FIRECRAWL_API_KEY')
366
+ if not api_key:
367
+ pytest.skip("需要设置 FIRECRAWL_API_KEY 环境变量来运行集成测试")
368
+ return api_key
369
+
370
+ @pytest.fixture
371
+ def mock_agent(self):
372
+ """创建 mock agent"""
373
+ agent = Mock()
374
+ agent.rag = Mock()
375
+ return agent
376
+
377
+ @pytest.fixture
378
+ def real_args(self, real_api_key):
379
+ """创建真实 args"""
380
+ args = Mock()
381
+ args.firecrawl_api_key = real_api_key
382
+ return args
383
+
384
+ @pytest.mark.integration
385
+ @pytest.mark.skipif(not os.getenv('FIRECRAWL_API_KEY'), reason="需要 FIRECRAWL_API_KEY 环境变量")
386
+ def test_real_web_search(self, mock_agent, real_args):
387
+ """实际调用 Firecrawl API 进行网页搜索"""
388
+ try:
389
+ # 导入真实的 Firecrawl SDK
390
+ from firecrawl import Firecrawl
391
+ except ImportError:
392
+ pytest.skip("需要安装 firecrawl-py: pip install firecrawl-py")
393
+
394
+ # 创建搜索工具 - 使用相对稳定的搜索词
395
+ search_tool = WebSearchTool(
396
+ query="python programming tutorial",
397
+ limit=3,
398
+ sources=["web"]
399
+ )
400
+
401
+ resolver = WebSearchToolResolver(mock_agent, search_tool, real_args)
402
+
403
+ # 执行实际搜索 - 设置超时
404
+ import time
405
+ start_time = time.time()
406
+ result = resolver.resolve()
407
+ end_time = time.time()
408
+
409
+ # 基本断言
410
+ assert isinstance(result, ToolResult)
411
+ print(f"\n=== 实际搜索结果 (耗时: {end_time - start_time:.2f}s) ===")
412
+ print(f"成功: {result.success}")
413
+ print(f"消息: {result.message}")
414
+
415
+ if result.success:
416
+ print(f"结果数量: {len(result.content)}")
417
+
418
+ # 集成测试可能因为各种外部因素(API配额、网络、服务状态等)返回空结果
419
+ # 这是可以接受的,我们主要验证API调用机制正常工作
420
+ if len(result.content) > 0:
421
+ print("✓ 返回了搜索结果,验证数据结构")
422
+ assert len(result.content) <= 3, "不应该超过限制的结果数量"
423
+
424
+ # 验证第一个结果的数据结构
425
+ first_result = result.content[0]
426
+ assert 'type' in first_result, "结果应该包含 type 字段"
427
+ assert first_result['type'] == 'web', "搜索结果类型应该是 web"
428
+ assert 'title' in first_result, "结果应该包含 title 字段"
429
+ assert 'url' in first_result, "结果应该包含 url 字段"
430
+ assert 'description' in first_result, "结果应该包含 description 字段"
431
+
432
+ # 打印前两个结果用于手动验证
433
+ for i, item in enumerate(result.content[:2]):
434
+ print(f"\n结果 {i+1}:")
435
+ print(f" 标题: {item.get('title', 'N/A')}")
436
+ print(f" URL: {item.get('url', 'N/A')}")
437
+ print(f" 描述: {item.get('description', 'N/A')[:100]}...")
438
+ if 'content' in item:
439
+ print(f" 内容长度: {len(item['content'])} 字符")
440
+ else:
441
+ print("⚠ 没有返回搜索结果 - 可能是API配额、网络或服务状态影响")
442
+ print("这在集成测试中是可以接受的,主要验证API调用机制正常")
443
+ else:
444
+ print(f"搜索失败: {result.message}")
445
+ # 打印错误内容用于调试
446
+ if result.content:
447
+ print(f"错误详情: {result.content}")
448
+ # 集成测试失败也是可接受的,因为依赖外部服务
449
+ print("注意: 集成测试失败可能由外部因素导致(网络、API限制等)")
450
+
451
+ @pytest.mark.integration
452
+ @pytest.mark.skipif(not os.getenv('FIRECRAWL_API_KEY'), reason="需要 FIRECRAWL_API_KEY 环境变量")
453
+ def test_real_image_search(self, mock_agent, real_args):
454
+ """实际调用 Firecrawl API 进行图片搜索"""
455
+ try:
456
+ from firecrawl import Firecrawl
457
+ except ImportError:
458
+ pytest.skip("需要安装 firecrawl-py: pip install firecrawl-py")
459
+
460
+ # 创建图片搜索工具
461
+ image_tool = WebSearchTool(
462
+ query="python logo",
463
+ limit=2,
464
+ sources=["images"]
465
+ )
466
+
467
+ resolver = WebSearchToolResolver(mock_agent, image_tool, real_args)
468
+
469
+ # 执行实际搜索
470
+ import time
471
+ start_time = time.time()
472
+ result = resolver.resolve()
473
+ end_time = time.time()
474
+
475
+ print(f"\n=== 实际图片搜索结果 (耗时: {end_time - start_time:.2f}s) ===")
476
+ print(f"成功: {result.success}")
477
+ print(f"消息: {result.message}")
478
+
479
+ if result.success and len(result.content) > 0:
480
+ print(f"图片数量: {len(result.content)}")
481
+
482
+ # 验证图片结果结构
483
+ first_image = result.content[0]
484
+ assert first_image['type'] == 'image', "结果类型应该是 image"
485
+ assert 'imageUrl' in first_image, "应该包含 imageUrl"
486
+ assert 'title' in first_image, "应该包含 title"
487
+
488
+ # 打印第一个图片结果
489
+ print(f" 标题: {first_image.get('title', 'N/A')}")
490
+ print(f" 图片URL: {first_image.get('imageUrl', 'N/A')}")
491
+ print(f" 来源URL: {first_image.get('url', 'N/A')}")
492
+ if 'imageWidth' in first_image and 'imageHeight' in first_image:
493
+ print(f" 尺寸: {first_image['imageWidth']}x{first_image['imageHeight']}")
494
+
495
+
496
+ class TestWebSearchToolRegistry:
497
+ """WebSearchTool 注册功能测试"""
498
+
499
+ def test_register_web_search_tool(self):
500
+ """测试工具注册功能"""
501
+ # 这个测试比较简单,主要确保注册函数能正常调用
502
+ # 具体的注册逻辑测试应该在 ToolRegistry 的测试中
503
+ try:
504
+ register_web_search_tool()
505
+ # 如果没有异常,说明注册成功
506
+ assert True
507
+ except Exception as e:
508
+ # 如果有异常,测试失败
509
+ pytest.fail(f"Tool registration failed: {str(e)}")