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.
- auto_coder-2.0.1.dist-info/LICENSE +158 -0
- auto_coder-2.0.1.dist-info/METADATA +558 -0
- auto_coder-2.0.1.dist-info/RECORD +795 -0
- {auto_coder-1.0.0.dist-info → auto_coder-2.0.1.dist-info}/WHEEL +1 -1
- {auto_coder-1.0.0.dist-info → auto_coder-2.0.1.dist-info}/entry_points.txt +3 -3
- autocoder/__init__.py +31 -0
- autocoder/agent/auto_filegroup.py +32 -13
- autocoder/agent/auto_learn_from_commit.py +9 -1
- autocoder/agent/base_agentic/__init__.py +3 -0
- autocoder/agent/base_agentic/agent_hub.py +1 -1
- autocoder/agent/base_agentic/base_agent.py +235 -136
- autocoder/agent/base_agentic/default_tools.py +119 -118
- autocoder/agent/base_agentic/test_base_agent.py +1 -1
- autocoder/agent/base_agentic/tool_registry.py +32 -20
- autocoder/agent/base_agentic/tools/read_file_tool_resolver.py +24 -3
- autocoder/agent/base_agentic/tools/write_to_file_tool_resolver.py +24 -11
- autocoder/agent/base_agentic/types.py +42 -0
- autocoder/agent/entry_command_agent/chat.py +77 -73
- autocoder/auto_coder.py +31 -40
- autocoder/auto_coder_rag.py +11 -1084
- autocoder/auto_coder_runner.py +962 -2345
- autocoder/auto_coder_terminal.py +26 -0
- autocoder/auto_coder_terminal_v3.py +190 -0
- autocoder/chat/conf_command.py +224 -124
- autocoder/chat/models_command.py +361 -299
- autocoder/chat/rules_command.py +79 -31
- autocoder/chat_auto_coder.py +988 -398
- autocoder/chat_auto_coder_lang.py +23 -732
- autocoder/commands/auto_command.py +25 -8
- autocoder/commands/auto_web.py +1 -1
- autocoder/commands/tools.py +44 -44
- autocoder/common/__init__.py +150 -128
- autocoder/common/ac_style_command_parser/__init__.py +39 -2
- autocoder/common/ac_style_command_parser/config.py +422 -0
- autocoder/common/ac_style_command_parser/parser.py +292 -78
- autocoder/common/ac_style_command_parser/test_parser.py +241 -16
- autocoder/common/ac_style_command_parser/test_typed_parser.py +342 -0
- autocoder/common/ac_style_command_parser/typed_parser.py +653 -0
- autocoder/common/action_yml_file_manager.py +25 -13
- autocoder/common/agent_events/__init__.py +52 -0
- autocoder/common/agent_events/agent_event_emitter.py +193 -0
- autocoder/common/agent_events/event_factory.py +177 -0
- autocoder/common/agent_events/examples.py +307 -0
- autocoder/common/agent_events/types.py +113 -0
- autocoder/common/agent_events/utils.py +68 -0
- autocoder/common/agent_hooks/__init__.py +44 -0
- autocoder/common/agent_hooks/examples.py +582 -0
- autocoder/common/agent_hooks/hook_executor.py +217 -0
- autocoder/common/agent_hooks/hook_manager.py +288 -0
- autocoder/common/agent_hooks/types.py +133 -0
- autocoder/common/agent_hooks/utils.py +99 -0
- autocoder/common/agent_query_queue/queue_executor.py +324 -0
- autocoder/common/agent_query_queue/queue_manager.py +325 -0
- autocoder/common/agents/__init__.py +11 -0
- autocoder/common/agents/agent_manager.py +323 -0
- autocoder/common/agents/agent_parser.py +189 -0
- autocoder/common/agents/example_usage.py +344 -0
- autocoder/common/agents/integration_example.py +330 -0
- autocoder/common/agents/test_agent_parser.py +545 -0
- autocoder/common/async_utils.py +101 -0
- autocoder/common/auto_coder_lang.py +23 -972
- autocoder/common/autocoderargs_parser/__init__.py +14 -0
- autocoder/common/autocoderargs_parser/parser.py +184 -0
- autocoder/common/autocoderargs_parser/tests/__init__.py +1 -0
- autocoder/common/autocoderargs_parser/tests/test_args_parser.py +235 -0
- autocoder/common/autocoderargs_parser/tests/test_token_parser.py +195 -0
- autocoder/common/autocoderargs_parser/token_parser.py +290 -0
- autocoder/common/buildin_tokenizer.py +2 -4
- autocoder/common/code_auto_generate.py +149 -74
- autocoder/common/code_auto_generate_diff.py +163 -70
- autocoder/common/code_auto_generate_editblock.py +179 -89
- autocoder/common/code_auto_generate_strict_diff.py +167 -72
- autocoder/common/code_auto_merge_editblock.py +13 -6
- autocoder/common/code_modification_ranker.py +1 -1
- autocoder/common/command_completer.py +3 -3
- autocoder/common/command_file_manager/manager.py +183 -47
- autocoder/common/command_file_manager/test_command_file_manager.py +507 -0
- autocoder/common/command_templates.py +1 -1
- autocoder/common/conf_utils.py +2 -4
- autocoder/common/conversations/config.py +11 -3
- autocoder/common/conversations/get_conversation_manager.py +100 -2
- autocoder/common/conversations/llm_stats_models.py +264 -0
- autocoder/common/conversations/manager.py +112 -28
- autocoder/common/conversations/models.py +16 -2
- autocoder/common/conversations/storage/index_manager.py +134 -10
- autocoder/common/core_config/__init__.py +63 -0
- autocoder/common/core_config/agentic_mode_manager.py +109 -0
- autocoder/common/core_config/base_manager.py +123 -0
- autocoder/common/core_config/compatibility.py +151 -0
- autocoder/common/core_config/config_manager.py +156 -0
- autocoder/common/core_config/conversation_manager.py +31 -0
- autocoder/common/core_config/exclude_manager.py +72 -0
- autocoder/common/core_config/file_manager.py +177 -0
- autocoder/common/core_config/human_as_model_manager.py +129 -0
- autocoder/common/core_config/lib_manager.py +54 -0
- autocoder/common/core_config/main_manager.py +81 -0
- autocoder/common/core_config/mode_manager.py +126 -0
- autocoder/common/core_config/models.py +70 -0
- autocoder/common/core_config/test_memory_manager.py +1056 -0
- autocoder/common/env_manager.py +282 -0
- autocoder/common/env_manager_usage_example.py +211 -0
- autocoder/common/file_checkpoint/conversation_checkpoint.py +19 -19
- autocoder/common/file_checkpoint/manager.py +264 -48
- autocoder/common/file_checkpoint/test_backup.py +1 -18
- autocoder/common/file_checkpoint/test_manager.py +270 -1
- autocoder/common/file_checkpoint/test_store.py +1 -17
- autocoder/common/file_handler/__init__.py +23 -0
- autocoder/common/file_handler/active_context_handler.py +159 -0
- autocoder/common/file_handler/add_files_handler.py +409 -0
- autocoder/common/file_handler/chat_handler.py +180 -0
- autocoder/common/file_handler/coding_handler.py +409 -0
- autocoder/common/file_handler/commit_handler.py +200 -0
- autocoder/common/file_handler/lib_handler.py +156 -0
- autocoder/common/file_handler/list_files_handler.py +111 -0
- autocoder/common/file_handler/mcp_handler.py +268 -0
- autocoder/common/file_handler/models_handler.py +493 -0
- autocoder/common/file_handler/remove_files_handler.py +172 -0
- autocoder/common/git_utils.py +44 -8
- autocoder/common/global_cancel.py +15 -6
- autocoder/common/ignorefiles/test_ignore_file_utils.py +1 -1
- autocoder/common/international/__init__.py +31 -0
- autocoder/common/international/demo_international.py +92 -0
- autocoder/common/international/message_manager.py +157 -0
- autocoder/common/international/messages/__init__.py +56 -0
- autocoder/common/international/messages/async_command_messages.py +507 -0
- autocoder/common/international/messages/auto_coder_messages.py +2208 -0
- autocoder/common/international/messages/chat_auto_coder_messages.py +1547 -0
- autocoder/common/international/messages/command_help_messages.py +986 -0
- autocoder/common/international/messages/conversation_command_messages.py +191 -0
- autocoder/common/international/messages/git_helper_plugin_messages.py +159 -0
- autocoder/common/international/messages/queue_command_messages.py +751 -0
- autocoder/common/international/messages/rules_command_messages.py +77 -0
- autocoder/common/international/messages/sdk_messages.py +1707 -0
- autocoder/common/international/messages/token_helper_plugin_messages.py +361 -0
- autocoder/common/international/messages/tool_display_messages.py +1212 -0
- autocoder/common/international/messages/workflow_exception_messages.py +473 -0
- autocoder/common/international/test_international.py +612 -0
- autocoder/common/linter_core/__init__.py +28 -0
- autocoder/common/linter_core/base_linter.py +61 -0
- autocoder/common/linter_core/config_loader.py +271 -0
- autocoder/common/linter_core/formatters/__init__.py +0 -0
- autocoder/common/linter_core/formatters/base_formatter.py +38 -0
- autocoder/common/linter_core/formatters/raw_formatter.py +17 -0
- autocoder/common/linter_core/linter.py +166 -0
- autocoder/common/linter_core/linter_factory.py +216 -0
- autocoder/common/linter_core/linter_manager.py +333 -0
- autocoder/common/linter_core/linters/__init__.py +9 -0
- autocoder/common/linter_core/linters/java_linter.py +342 -0
- autocoder/common/linter_core/linters/python_linter.py +115 -0
- autocoder/common/linter_core/linters/typescript_linter.py +119 -0
- autocoder/common/linter_core/models/__init__.py +7 -0
- autocoder/common/linter_core/models/lint_result.py +91 -0
- autocoder/common/linter_core/models.py +33 -0
- autocoder/common/linter_core/tests/__init__.py +3 -0
- autocoder/common/linter_core/tests/test_config_loader.py +323 -0
- autocoder/common/linter_core/tests/test_config_loading.py +308 -0
- autocoder/common/linter_core/tests/test_factory_manager.py +234 -0
- autocoder/common/linter_core/tests/test_formatters.py +147 -0
- autocoder/common/linter_core/tests/test_integration.py +317 -0
- autocoder/common/linter_core/tests/test_java_linter.py +496 -0
- autocoder/common/linter_core/tests/test_linters.py +265 -0
- autocoder/common/linter_core/tests/test_models.py +81 -0
- autocoder/common/linter_core/tests/verify_config_loading.py +296 -0
- autocoder/common/linter_core/tests/verify_fixes.py +183 -0
- autocoder/common/llm_friendly_package/__init__.py +31 -0
- autocoder/common/llm_friendly_package/base_manager.py +102 -0
- autocoder/common/llm_friendly_package/docs_manager.py +121 -0
- autocoder/common/llm_friendly_package/library_manager.py +171 -0
- autocoder/common/{llm_friendly_package.py → llm_friendly_package/main_manager.py} +204 -231
- autocoder/common/llm_friendly_package/models.py +40 -0
- autocoder/common/llm_friendly_package/test_llm_friendly_package.py +536 -0
- autocoder/common/llms/__init__.py +15 -0
- autocoder/common/llms/demo_error_handling.py +85 -0
- autocoder/common/llms/factory.py +142 -0
- autocoder/common/llms/manager.py +264 -0
- autocoder/common/llms/pricing.py +121 -0
- autocoder/common/llms/registry.py +316 -0
- autocoder/common/llms/schema.py +77 -0
- autocoder/common/llms/simple_demo.py +45 -0
- autocoder/common/llms/test_quick_model.py +116 -0
- autocoder/common/llms/test_remove_functionality.py +182 -0
- autocoder/common/llms/tests/__init__.py +1 -0
- autocoder/common/llms/tests/test_manager.py +330 -0
- autocoder/common/llms/tests/test_registry.py +364 -0
- autocoder/common/mcp_tools/__init__.py +62 -0
- autocoder/common/{mcp_tools.py → mcp_tools/executor.py} +49 -40
- autocoder/common/{mcp_hub.py → mcp_tools/hub.py} +42 -68
- autocoder/common/{mcp_server_install.py → mcp_tools/installer.py} +16 -28
- autocoder/common/{mcp_server.py → mcp_tools/server.py} +176 -48
- autocoder/common/mcp_tools/test_keyboard_interrupt.py +93 -0
- autocoder/common/mcp_tools/test_mcp_tools.py +391 -0
- autocoder/common/{mcp_server_types.py → mcp_tools/types.py} +121 -48
- autocoder/common/mcp_tools/verify_functionality.py +202 -0
- autocoder/common/model_speed_tester.py +32 -26
- autocoder/common/priority_directory_finder/__init__.py +142 -0
- autocoder/common/priority_directory_finder/examples.py +230 -0
- autocoder/common/priority_directory_finder/finder.py +283 -0
- autocoder/common/priority_directory_finder/models.py +236 -0
- autocoder/common/priority_directory_finder/test_priority_directory_finder.py +431 -0
- autocoder/common/project_scanner/__init__.py +18 -0
- autocoder/common/project_scanner/compat.py +77 -0
- autocoder/common/project_scanner/scanner.py +436 -0
- autocoder/common/project_tracker/__init__.py +27 -0
- autocoder/common/project_tracker/api.py +228 -0
- autocoder/common/project_tracker/demo.py +272 -0
- autocoder/common/project_tracker/tracker.py +487 -0
- autocoder/common/project_tracker/types.py +53 -0
- autocoder/common/pruner/__init__.py +67 -0
- autocoder/common/pruner/agentic_conversation_pruner.py +651 -102
- autocoder/common/pruner/conversation_message_ids_api.py +386 -0
- autocoder/common/pruner/conversation_message_ids_manager.py +347 -0
- autocoder/common/pruner/conversation_message_ids_pruner.py +473 -0
- autocoder/common/pruner/conversation_normalizer.py +347 -0
- autocoder/common/pruner/conversation_pruner.py +26 -6
- autocoder/common/pruner/test_agentic_conversation_pruner.py +554 -112
- autocoder/common/pruner/test_conversation_normalizer.py +502 -0
- autocoder/common/pruner/test_tool_content_detector.py +324 -0
- autocoder/common/pruner/tool_content_detector.py +227 -0
- autocoder/common/pruner/tools/__init__.py +18 -0
- autocoder/common/pruner/tools/query_message_ids.py +264 -0
- autocoder/common/pruner/tools/test_agentic_pruning_logic.py +432 -0
- autocoder/common/pruner/tools/test_message_ids_pruning_only.py +192 -0
- autocoder/common/pull_requests/__init__.py +9 -1
- autocoder/common/pull_requests/utils.py +122 -1
- autocoder/common/rag_manager/rag_manager.py +36 -40
- autocoder/common/rulefiles/__init__.py +53 -1
- autocoder/common/rulefiles/api.py +250 -0
- autocoder/common/rulefiles/core/__init__.py +14 -0
- autocoder/common/rulefiles/core/manager.py +241 -0
- autocoder/common/rulefiles/core/selector.py +805 -0
- autocoder/common/rulefiles/models/__init__.py +20 -0
- autocoder/common/rulefiles/models/index.py +16 -0
- autocoder/common/rulefiles/models/init_rule.py +18 -0
- autocoder/common/rulefiles/models/rule_file.py +18 -0
- autocoder/common/rulefiles/models/rule_relevance.py +14 -0
- autocoder/common/rulefiles/models/summary.py +16 -0
- autocoder/common/rulefiles/test_rulefiles.py +776 -0
- autocoder/common/rulefiles/utils/__init__.py +34 -0
- autocoder/common/rulefiles/utils/monitor.py +86 -0
- autocoder/common/rulefiles/utils/parser.py +230 -0
- autocoder/common/save_formatted_log.py +67 -10
- autocoder/common/search_replace.py +8 -1
- autocoder/common/search_replace_patch/__init__.py +24 -0
- autocoder/common/search_replace_patch/base.py +115 -0
- autocoder/common/search_replace_patch/manager.py +248 -0
- autocoder/common/search_replace_patch/patch_replacer.py +304 -0
- autocoder/common/search_replace_patch/similarity_replacer.py +306 -0
- autocoder/common/search_replace_patch/string_replacer.py +181 -0
- autocoder/common/search_replace_patch/tests/__init__.py +3 -0
- autocoder/common/search_replace_patch/tests/run_tests.py +126 -0
- autocoder/common/search_replace_patch/tests/test_base.py +188 -0
- autocoder/common/search_replace_patch/tests/test_empty_line_insert.py +233 -0
- autocoder/common/search_replace_patch/tests/test_integration.py +389 -0
- autocoder/common/search_replace_patch/tests/test_manager.py +351 -0
- autocoder/common/search_replace_patch/tests/test_patch_replacer.py +316 -0
- autocoder/common/search_replace_patch/tests/test_regex_replacer.py +306 -0
- autocoder/common/search_replace_patch/tests/test_similarity_replacer.py +384 -0
- autocoder/common/shell_commands/__init__.py +197 -0
- autocoder/common/shell_commands/background_process_notifier.py +346 -0
- autocoder/common/shell_commands/command_executor.py +1127 -0
- autocoder/common/shell_commands/error_recovery.py +541 -0
- autocoder/common/shell_commands/exceptions.py +120 -0
- autocoder/common/shell_commands/interactive_executor.py +476 -0
- autocoder/common/shell_commands/interactive_pexpect_process.py +623 -0
- autocoder/common/shell_commands/interactive_process.py +744 -0
- autocoder/common/shell_commands/interactive_session_manager.py +1014 -0
- autocoder/common/shell_commands/monitoring.py +529 -0
- autocoder/common/shell_commands/process_cleanup.py +386 -0
- autocoder/common/shell_commands/process_manager.py +606 -0
- autocoder/common/shell_commands/test_interactive_pexpect_process.py +281 -0
- autocoder/common/shell_commands/tests/__init__.py +6 -0
- autocoder/common/shell_commands/tests/conftest.py +118 -0
- autocoder/common/shell_commands/tests/test_background_process_notifier.py +703 -0
- autocoder/common/shell_commands/tests/test_command_executor.py +448 -0
- autocoder/common/shell_commands/tests/test_error_recovery.py +305 -0
- autocoder/common/shell_commands/tests/test_exceptions.py +299 -0
- autocoder/common/shell_commands/tests/test_execute_batch.py +588 -0
- autocoder/common/shell_commands/tests/test_indented_batch_commands.py +244 -0
- autocoder/common/shell_commands/tests/test_integration.py +664 -0
- autocoder/common/shell_commands/tests/test_monitoring.py +546 -0
- autocoder/common/shell_commands/tests/test_performance.py +632 -0
- autocoder/common/shell_commands/tests/test_process_cleanup.py +397 -0
- autocoder/common/shell_commands/tests/test_process_manager.py +606 -0
- autocoder/common/shell_commands/tests/test_timeout_config.py +343 -0
- autocoder/common/shell_commands/tests/test_timeout_manager.py +520 -0
- autocoder/common/shell_commands/timeout_config.py +315 -0
- autocoder/common/shell_commands/timeout_manager.py +352 -0
- autocoder/common/terminal_paste/__init__.py +14 -0
- autocoder/common/terminal_paste/demo.py +145 -0
- autocoder/common/terminal_paste/demo_paste_functionality.py +95 -0
- autocoder/common/terminal_paste/paste_handler.py +200 -0
- autocoder/common/terminal_paste/paste_manager.py +118 -0
- autocoder/common/terminal_paste/tests/__init__.py +1 -0
- autocoder/common/terminal_paste/tests/test_paste_handler.py +182 -0
- autocoder/common/terminal_paste/tests/test_paste_manager.py +126 -0
- autocoder/common/terminal_paste/utils.py +163 -0
- autocoder/common/test_autocoder_args.py +232 -0
- autocoder/common/test_env_manager.py +173 -0
- autocoder/common/test_env_manager_integration.py +159 -0
- autocoder/common/text_similarity/__init__.py +9 -0
- autocoder/common/text_similarity/demo.py +216 -0
- autocoder/common/text_similarity/examples.py +266 -0
- autocoder/common/text_similarity/test_text_similarity.py +306 -0
- autocoder/common/text_similarity/text_similarity.py +194 -0
- autocoder/common/text_similarity/utils.py +125 -0
- autocoder/common/todos/__init__.py +61 -0
- autocoder/common/todos/cache/__init__.py +16 -0
- autocoder/common/todos/cache/base_cache.py +89 -0
- autocoder/common/todos/cache/cache_manager.py +228 -0
- autocoder/common/todos/cache/memory_cache.py +225 -0
- autocoder/common/todos/config.py +155 -0
- autocoder/common/todos/exceptions.py +35 -0
- autocoder/common/todos/get_todo_manager.py +161 -0
- autocoder/common/todos/manager.py +537 -0
- autocoder/common/todos/models.py +239 -0
- autocoder/common/todos/storage/__init__.py +14 -0
- autocoder/common/todos/storage/base_storage.py +76 -0
- autocoder/common/todos/storage/file_storage.py +278 -0
- autocoder/common/tokens/counter.py +24 -2
- autocoder/common/tools_manager/__init__.py +17 -0
- autocoder/common/tools_manager/examples.py +162 -0
- autocoder/common/tools_manager/manager.py +385 -0
- autocoder/common/tools_manager/models.py +39 -0
- autocoder/common/tools_manager/test_tools_manager.py +303 -0
- autocoder/common/tools_manager/utils.py +191 -0
- autocoder/common/v2/agent/agentic_callbacks.py +270 -0
- autocoder/common/v2/agent/agentic_edit.py +2699 -1856
- autocoder/common/v2/agent/agentic_edit_change_manager.py +474 -0
- autocoder/common/v2/agent/agentic_edit_tools/__init__.py +35 -1
- autocoder/common/v2/agent/agentic_edit_tools/ac_mod_list_tool_resolver.py +279 -0
- autocoder/common/v2/agent/agentic_edit_tools/ac_mod_write_tool_resolver.py +10 -1
- autocoder/common/v2/agent/agentic_edit_tools/background_task_tool_resolver.py +1167 -0
- autocoder/common/v2/agent/agentic_edit_tools/base_tool_resolver.py +2 -2
- autocoder/common/v2/agent/agentic_edit_tools/conversation_message_ids_read_tool_resolver.py +214 -0
- autocoder/common/v2/agent/agentic_edit_tools/conversation_message_ids_write_tool_resolver.py +299 -0
- autocoder/common/v2/agent/agentic_edit_tools/count_tokens_tool_resolver.py +290 -0
- autocoder/common/v2/agent/agentic_edit_tools/execute_command_tool_resolver.py +564 -29
- autocoder/common/v2/agent/agentic_edit_tools/execute_workflow_tool_resolver.py +485 -0
- autocoder/common/v2/agent/agentic_edit_tools/extract_to_text_tool_resolver.py +225 -0
- autocoder/common/v2/agent/agentic_edit_tools/lint_report.py +79 -0
- autocoder/common/v2/agent/agentic_edit_tools/linter_config_models.py +343 -0
- autocoder/common/v2/agent/agentic_edit_tools/linter_enabled_tool_resolver.py +189 -0
- autocoder/common/v2/agent/agentic_edit_tools/list_files_tool_resolver.py +169 -101
- autocoder/common/v2/agent/agentic_edit_tools/load_extra_document_tool_resolver.py +356 -0
- autocoder/common/v2/agent/agentic_edit_tools/read_file_tool_resolver.py +243 -50
- autocoder/common/v2/agent/agentic_edit_tools/replace_in_file_tool_resolver.py +667 -147
- autocoder/common/v2/agent/agentic_edit_tools/run_named_subagents_tool_resolver.py +691 -0
- autocoder/common/v2/agent/agentic_edit_tools/search_files_tool_resolver.py +410 -86
- autocoder/common/v2/agent/agentic_edit_tools/session_interactive_tool_resolver.py +115 -0
- autocoder/common/v2/agent/agentic_edit_tools/session_start_tool_resolver.py +190 -0
- autocoder/common/v2/agent/agentic_edit_tools/session_stop_tool_resolver.py +76 -0
- autocoder/common/v2/agent/agentic_edit_tools/test_write_to_file_tool_resolver.py +207 -192
- autocoder/common/v2/agent/agentic_edit_tools/todo_read_tool_resolver.py +80 -63
- autocoder/common/v2/agent/agentic_edit_tools/todo_write_tool_resolver.py +237 -233
- autocoder/common/v2/agent/agentic_edit_tools/use_mcp_tool_resolver.py +2 -2
- autocoder/common/v2/agent/agentic_edit_tools/web_crawl_tool_resolver.py +557 -0
- autocoder/common/v2/agent/agentic_edit_tools/web_search_tool_resolver.py +600 -0
- autocoder/common/v2/agent/agentic_edit_tools/write_to_file_tool_resolver.py +56 -121
- autocoder/common/v2/agent/agentic_edit_types.py +343 -9
- autocoder/common/v2/agent/runner/__init__.py +3 -3
- autocoder/common/v2/agent/runner/base_runner.py +12 -26
- autocoder/common/v2/agent/runner/{event_runner.py → file_based_event_runner.py} +3 -2
- autocoder/common/v2/agent/runner/sdk_runner.py +150 -8
- autocoder/common/v2/agent/runner/terminal_runner.py +170 -57
- autocoder/common/v2/agent/runner/tool_display.py +557 -159
- autocoder/common/v2/agent/test_agentic_callbacks.py +265 -0
- autocoder/common/v2/agent/test_agentic_edit.py +194 -0
- autocoder/common/v2/agent/tool_caller/__init__.py +24 -0
- autocoder/common/v2/agent/tool_caller/default_tool_resolver_map.py +135 -0
- autocoder/common/v2/agent/tool_caller/integration_test.py +172 -0
- autocoder/common/v2/agent/tool_caller/plugins/__init__.py +14 -0
- autocoder/common/v2/agent/tool_caller/plugins/base_plugin.py +126 -0
- autocoder/common/v2/agent/tool_caller/plugins/examples/__init__.py +13 -0
- autocoder/common/v2/agent/tool_caller/plugins/examples/logging_plugin.py +164 -0
- autocoder/common/v2/agent/tool_caller/plugins/examples/security_filter_plugin.py +198 -0
- autocoder/common/v2/agent/tool_caller/plugins/plugin_interface.py +141 -0
- autocoder/common/v2/agent/tool_caller/test_tool_caller.py +278 -0
- autocoder/common/v2/agent/tool_caller/tool_call_plugin_manager.py +331 -0
- autocoder/common/v2/agent/tool_caller/tool_caller.py +337 -0
- autocoder/common/v2/agent/tool_caller/usage_example.py +193 -0
- autocoder/common/v2/code_agentic_editblock_manager.py +4 -4
- autocoder/common/v2/code_auto_generate.py +136 -78
- autocoder/common/v2/code_auto_generate_diff.py +135 -79
- autocoder/common/v2/code_auto_generate_editblock.py +174 -99
- autocoder/common/v2/code_auto_generate_strict_diff.py +151 -71
- autocoder/common/v2/code_auto_merge.py +1 -1
- autocoder/common/v2/code_auto_merge_editblock.py +13 -1
- autocoder/common/v2/code_diff_manager.py +3 -3
- autocoder/common/v2/code_editblock_manager.py +4 -14
- autocoder/common/v2/code_manager.py +1 -1
- autocoder/common/v2/code_strict_diff_manager.py +2 -2
- autocoder/common/wrap_llm_hint/__init__.py +10 -0
- autocoder/common/wrap_llm_hint/test_wrap_llm_hint.py +1067 -0
- autocoder/common/wrap_llm_hint/utils.py +432 -0
- autocoder/common/wrap_llm_hint/wrap_llm_hint.py +323 -0
- autocoder/completer/__init__.py +8 -0
- autocoder/completer/command_completer_v2.py +1094 -0
- autocoder/default_project/__init__.py +501 -0
- autocoder/dispacher/__init__.py +4 -12
- autocoder/dispacher/actions/action.py +400 -129
- autocoder/dispacher/actions/plugins/action_regex_project.py +2 -2
- autocoder/index/entry.py +117 -125
- autocoder/{agent → index/filter}/agentic_filter.py +322 -333
- autocoder/index/filter/normal_filter.py +5 -11
- autocoder/index/filter/quick_filter.py +1 -1
- autocoder/index/index.py +36 -9
- autocoder/index/tests/__init__.py +1 -0
- autocoder/index/tests/run_tests.py +195 -0
- autocoder/index/tests/test_entry.py +303 -0
- autocoder/index/tests/test_index_manager.py +314 -0
- autocoder/index/tests/test_module_integration.py +300 -0
- autocoder/index/tests/test_symbols_utils.py +183 -0
- autocoder/inner/__init__.py +4 -0
- autocoder/inner/agentic.py +923 -0
- autocoder/inner/async_command_handler.py +992 -0
- autocoder/inner/conversation_command_handlers.py +623 -0
- autocoder/inner/merge_command_handler.py +213 -0
- autocoder/inner/queue_command_handler.py +684 -0
- autocoder/models.py +95 -266
- autocoder/plugins/git_helper_plugin.py +31 -29
- autocoder/plugins/token_helper_plugin.py +65 -46
- autocoder/pyproject/__init__.py +32 -29
- autocoder/rag/agentic_rag.py +215 -75
- autocoder/rag/cache/simple_cache.py +1 -2
- autocoder/rag/loaders/image_loader.py +1 -1
- autocoder/rag/long_context_rag.py +42 -26
- autocoder/rag/qa_conversation_strategy.py +1 -1
- autocoder/rag/terminal/__init__.py +17 -0
- autocoder/rag/terminal/args.py +581 -0
- autocoder/rag/terminal/bootstrap.py +61 -0
- autocoder/rag/terminal/command_handlers.py +653 -0
- autocoder/rag/terminal/formatters/__init__.py +20 -0
- autocoder/rag/terminal/formatters/base.py +70 -0
- autocoder/rag/terminal/formatters/json_format.py +66 -0
- autocoder/rag/terminal/formatters/stream_json.py +95 -0
- autocoder/rag/terminal/formatters/text.py +28 -0
- autocoder/rag/terminal/init.py +120 -0
- autocoder/rag/terminal/utils.py +106 -0
- autocoder/rag/test_agentic_rag.py +389 -0
- autocoder/rag/test_doc_filter.py +3 -3
- autocoder/rag/test_long_context_rag.py +1 -1
- autocoder/rag/test_token_limiter.py +517 -10
- autocoder/rag/token_counter.py +3 -0
- autocoder/rag/token_limiter.py +19 -15
- autocoder/rag/tools/__init__.py +26 -2
- autocoder/rag/tools/bochaai_example.py +343 -0
- autocoder/rag/tools/bochaai_sdk.py +541 -0
- autocoder/rag/tools/metaso_example.py +268 -0
- autocoder/rag/tools/metaso_sdk.py +417 -0
- autocoder/rag/tools/recall_tool.py +28 -7
- autocoder/rag/tools/run_integration_tests.py +204 -0
- autocoder/rag/tools/test_all_providers.py +318 -0
- autocoder/rag/tools/test_bochaai_integration.py +482 -0
- autocoder/rag/tools/test_final_integration.py +215 -0
- autocoder/rag/tools/test_metaso_integration.py +424 -0
- autocoder/rag/tools/test_metaso_real.py +171 -0
- autocoder/rag/tools/test_web_crawl_tool.py +639 -0
- autocoder/rag/tools/test_web_search_tool.py +509 -0
- autocoder/rag/tools/todo_read_tool.py +202 -0
- autocoder/rag/tools/todo_write_tool.py +412 -0
- autocoder/rag/tools/web_crawl_tool.py +634 -0
- autocoder/rag/tools/web_search_tool.py +558 -0
- autocoder/rag/tools/web_tools_example.py +119 -0
- autocoder/rag/types.py +16 -0
- autocoder/rag/variable_holder.py +4 -2
- autocoder/rags.py +86 -79
- autocoder/regexproject/__init__.py +23 -21
- autocoder/sdk/__init__.py +46 -190
- autocoder/sdk/api.py +370 -0
- autocoder/sdk/async_runner/__init__.py +26 -0
- autocoder/sdk/async_runner/async_executor.py +650 -0
- autocoder/sdk/async_runner/async_handler.py +356 -0
- autocoder/sdk/async_runner/markdown_processor.py +595 -0
- autocoder/sdk/async_runner/task_metadata.py +284 -0
- autocoder/sdk/async_runner/worktree_manager.py +438 -0
- autocoder/sdk/cli/__init__.py +2 -5
- autocoder/sdk/cli/formatters.py +28 -204
- autocoder/sdk/cli/handlers.py +77 -44
- autocoder/sdk/cli/main.py +154 -171
- autocoder/sdk/cli/options.py +95 -22
- autocoder/sdk/constants.py +139 -51
- autocoder/sdk/core/auto_coder_core.py +484 -109
- autocoder/sdk/core/bridge.py +297 -115
- autocoder/sdk/exceptions.py +18 -12
- autocoder/sdk/formatters/__init__.py +19 -0
- autocoder/sdk/formatters/input.py +64 -0
- autocoder/sdk/formatters/output.py +247 -0
- autocoder/sdk/formatters/stream.py +54 -0
- autocoder/sdk/models/__init__.py +6 -5
- autocoder/sdk/models/options.py +55 -18
- autocoder/sdk/utils/formatters.py +27 -195
- autocoder/suffixproject/__init__.py +28 -25
- autocoder/terminal/__init__.py +14 -0
- autocoder/terminal/app.py +454 -0
- autocoder/terminal/args.py +32 -0
- autocoder/terminal/bootstrap.py +178 -0
- autocoder/terminal/command_processor.py +521 -0
- autocoder/terminal/command_registry.py +57 -0
- autocoder/terminal/help.py +97 -0
- autocoder/terminal/tasks/__init__.py +5 -0
- autocoder/terminal/tasks/background.py +77 -0
- autocoder/terminal/tasks/task_event.py +70 -0
- autocoder/terminal/ui/__init__.py +13 -0
- autocoder/terminal/ui/completer.py +268 -0
- autocoder/terminal/ui/keybindings.py +75 -0
- autocoder/terminal/ui/session.py +41 -0
- autocoder/terminal/ui/toolbar.py +64 -0
- autocoder/terminal/utils/__init__.py +13 -0
- autocoder/terminal/utils/errors.py +18 -0
- autocoder/terminal/utils/paths.py +19 -0
- autocoder/terminal/utils/shell.py +43 -0
- autocoder/terminal_v3/__init__.py +10 -0
- autocoder/terminal_v3/app.py +201 -0
- autocoder/terminal_v3/handlers/__init__.py +5 -0
- autocoder/terminal_v3/handlers/command_handler.py +131 -0
- autocoder/terminal_v3/models/__init__.py +6 -0
- autocoder/terminal_v3/models/conversation_buffer.py +214 -0
- autocoder/terminal_v3/models/message.py +50 -0
- autocoder/terminal_v3/models/tool_display.py +247 -0
- autocoder/terminal_v3/ui/__init__.py +7 -0
- autocoder/terminal_v3/ui/keybindings.py +56 -0
- autocoder/terminal_v3/ui/layout.py +141 -0
- autocoder/terminal_v3/ui/styles.py +43 -0
- autocoder/tsproject/__init__.py +23 -23
- autocoder/utils/auto_coder_utils/chat_stream_out.py +1 -1
- autocoder/utils/llms.py +88 -80
- autocoder/utils/math_utils.py +101 -0
- autocoder/utils/model_provider_selector.py +16 -4
- autocoder/utils/operate_config_api.py +33 -5
- autocoder/utils/thread_utils.py +2 -2
- autocoder/version.py +4 -2
- autocoder/workflow_agents/__init__.py +84 -0
- autocoder/workflow_agents/agent.py +143 -0
- autocoder/workflow_agents/exceptions.py +573 -0
- autocoder/workflow_agents/executor.py +665 -0
- autocoder/workflow_agents/loader.py +749 -0
- autocoder/workflow_agents/runner.py +267 -0
- autocoder/workflow_agents/types.py +173 -0
- autocoder/workflow_agents/utils.py +434 -0
- autocoder/workflow_agents/workflow_manager.py +211 -0
- auto_coder-1.0.0.dist-info/METADATA +0 -396
- auto_coder-1.0.0.dist-info/RECORD +0 -442
- auto_coder-1.0.0.dist-info/licenses/LICENSE +0 -201
- autocoder/auto_coder_server.py +0 -672
- autocoder/benchmark.py +0 -138
- autocoder/common/ac_style_command_parser/example.py +0 -7
- autocoder/common/cleaner.py +0 -31
- autocoder/common/command_completer_v2.py +0 -615
- autocoder/common/context_pruner.py +0 -477
- autocoder/common/conversation_pruner.py +0 -132
- autocoder/common/directory_cache/__init__.py +0 -1
- autocoder/common/directory_cache/cache.py +0 -192
- autocoder/common/directory_cache/test_cache.py +0 -190
- autocoder/common/file_checkpoint/examples.py +0 -217
- autocoder/common/llm_friendly_package_example.py +0 -138
- autocoder/common/llm_friendly_package_test.py +0 -63
- autocoder/common/pull_requests/test_module.py +0 -1
- autocoder/common/rulefiles/autocoderrules_utils.py +0 -484
- autocoder/common/text.py +0 -30
- autocoder/common/v2/agent/agentic_edit_tools/list_package_info_tool_resolver.py +0 -42
- autocoder/common/v2/agent/agentic_edit_tools/test_execute_command_tool_resolver.py +0 -70
- autocoder/common/v2/agent/agentic_edit_tools/test_search_files_tool_resolver.py +0 -163
- autocoder/common/v2/agent/agentic_tool_display.py +0 -183
- autocoder/plugins/dynamic_completion_example.py +0 -148
- autocoder/plugins/sample_plugin.py +0 -160
- autocoder/sdk/cli/__main__.py +0 -26
- autocoder/sdk/cli/completion_wrapper.py +0 -38
- autocoder/sdk/cli/install_completion.py +0 -301
- autocoder/sdk/models/messages.py +0 -209
- autocoder/sdk/session/__init__.py +0 -32
- autocoder/sdk/session/session.py +0 -106
- autocoder/sdk/session/session_manager.py +0 -56
- {auto_coder-1.0.0.dist-info → auto_coder-2.0.1.dist-info}/top_level.txt +0 -0
- /autocoder/{sdk/example.py → common/agent_query_queue/__init__.py} +0 -0
|
@@ -0,0 +1,558 @@
|
|
|
1
|
+
"""
|
|
2
|
+
WebSearchTool Module
|
|
3
|
+
|
|
4
|
+
This module implements the WebSearchTool and WebSearchToolResolver classes
|
|
5
|
+
for providing web search functionality based on Firecrawl, Metaso, or BochaAI
|
|
6
|
+
within the BaseAgent framework.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
import traceback
|
|
11
|
+
import json
|
|
12
|
+
from typing import Dict, Any, List, Optional
|
|
13
|
+
|
|
14
|
+
import byzerllm
|
|
15
|
+
from loguru import logger
|
|
16
|
+
from numpy import log
|
|
17
|
+
|
|
18
|
+
from autocoder.agent.base_agentic.types import BaseTool, ToolResult
|
|
19
|
+
from autocoder.agent.base_agentic.tool_registry import ToolRegistry
|
|
20
|
+
from autocoder.agent.base_agentic.tools.base_tool_resolver import BaseToolResolver
|
|
21
|
+
from autocoder.agent.base_agentic.types import ToolDescription, ToolExample
|
|
22
|
+
from autocoder.rag.tools.metaso_sdk import MetasoClient
|
|
23
|
+
from autocoder.rag.tools.bochaai_sdk import BochaAIClient
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class WebSearchTool(BaseTool):
|
|
27
|
+
"""Web search tool using Firecrawl, Metaso, or BochaAI for web search"""
|
|
28
|
+
query: str # Search query
|
|
29
|
+
limit: Optional[int] = 5 # Return result count limit
|
|
30
|
+
sources: Optional[str] = None # Search source types, comma-separated: web,news,images
|
|
31
|
+
scrape_options: Optional[str] = None # Scraping options, JSON string format
|
|
32
|
+
location: Optional[str] = None # Search location
|
|
33
|
+
tbs: Optional[str] = None # Time filter parameters
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class WebSearchToolResolver(BaseToolResolver):
|
|
37
|
+
"""Web search tool resolver that implements search logic"""
|
|
38
|
+
|
|
39
|
+
def __init__(self, agent, tool, args):
|
|
40
|
+
super().__init__(agent, tool, args)
|
|
41
|
+
self.tool: WebSearchTool = tool
|
|
42
|
+
|
|
43
|
+
def _search_with_bochaai(self) -> ToolResult:
|
|
44
|
+
"""Search using BochaAI"""
|
|
45
|
+
try:
|
|
46
|
+
# Check if BochaAI API key is provided
|
|
47
|
+
api_key = getattr(self.args, 'bochaai_api_key', None) or os.getenv('BOCHAAI_API_KEY')
|
|
48
|
+
if not api_key:
|
|
49
|
+
return ToolResult(
|
|
50
|
+
success=False,
|
|
51
|
+
message="BochaAI API key not provided, please set --bochaai_api_key parameter or BOCHAAI_API_KEY environment variable",
|
|
52
|
+
content=[]
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# Initialize BochaAI client
|
|
56
|
+
client = BochaAIClient(api_key=api_key)
|
|
57
|
+
|
|
58
|
+
# Prepare search parameters
|
|
59
|
+
freshness = "noLimit" # Default no time limit
|
|
60
|
+
if self.tool.tbs:
|
|
61
|
+
# Map time filter parameters
|
|
62
|
+
tbs_mapping = {
|
|
63
|
+
"d": "oneDay",
|
|
64
|
+
"w": "oneWeek",
|
|
65
|
+
"m": "oneMonth",
|
|
66
|
+
"y": "oneYear"
|
|
67
|
+
}
|
|
68
|
+
freshness = tbs_mapping.get(self.tool.tbs, "noLimit")
|
|
69
|
+
|
|
70
|
+
# Parse scrape_options to get additional parameters
|
|
71
|
+
include_summary = False
|
|
72
|
+
include_sites = None
|
|
73
|
+
exclude_sites = None
|
|
74
|
+
if self.tool.scrape_options:
|
|
75
|
+
try:
|
|
76
|
+
scrape_opts = json.loads(self.tool.scrape_options)
|
|
77
|
+
include_summary = scrape_opts.get('include_summary', False) or scrape_opts.get('summary', False)
|
|
78
|
+
include_sites = scrape_opts.get('include_sites')
|
|
79
|
+
exclude_sites = scrape_opts.get('exclude_sites')
|
|
80
|
+
except json.JSONDecodeError:
|
|
81
|
+
pass
|
|
82
|
+
|
|
83
|
+
# Execute search
|
|
84
|
+
logger.info(f"Performing web search using BochaAI, query: {self.tool.query}")
|
|
85
|
+
result = client.search(
|
|
86
|
+
query=self.tool.query,
|
|
87
|
+
count=self.tool.limit,
|
|
88
|
+
freshness=freshness,
|
|
89
|
+
summary=include_summary,
|
|
90
|
+
include=include_sites,
|
|
91
|
+
exclude=exclude_sites
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
if not result.success:
|
|
95
|
+
return ToolResult(
|
|
96
|
+
success=False,
|
|
97
|
+
message=f"BochaAI search failed: {result.error}",
|
|
98
|
+
content=[]
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
# Format search results
|
|
102
|
+
search_results = []
|
|
103
|
+
|
|
104
|
+
# Process web results
|
|
105
|
+
for webpage in result.webpages:
|
|
106
|
+
result_item = {
|
|
107
|
+
"type": "web",
|
|
108
|
+
"title": webpage.name,
|
|
109
|
+
"url": webpage.url,
|
|
110
|
+
"description": webpage.snippet,
|
|
111
|
+
"provider": "bochaai"
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if webpage.summary:
|
|
115
|
+
result_item["summary"] = webpage.summary
|
|
116
|
+
if webpage.date_published:
|
|
117
|
+
result_item["date"] = webpage.date_published
|
|
118
|
+
if webpage.site_name:
|
|
119
|
+
result_item["site_name"] = webpage.site_name
|
|
120
|
+
if webpage.site_icon:
|
|
121
|
+
result_item["site_icon"] = webpage.site_icon
|
|
122
|
+
|
|
123
|
+
search_results.append(result_item)
|
|
124
|
+
|
|
125
|
+
# Process image results (if needed)
|
|
126
|
+
if self.tool.sources and "images" in self.tool.sources:
|
|
127
|
+
for image in result.images:
|
|
128
|
+
image_item = {
|
|
129
|
+
"type": "image",
|
|
130
|
+
"url": image.content_url,
|
|
131
|
+
"thumbnail_url": image.thumbnail_url,
|
|
132
|
+
"host_page_url": image.host_page_url,
|
|
133
|
+
"width": image.width,
|
|
134
|
+
"height": image.height,
|
|
135
|
+
"provider": "bochaai"
|
|
136
|
+
}
|
|
137
|
+
if image.name:
|
|
138
|
+
image_item["title"] = image.name
|
|
139
|
+
search_results.append(image_item)
|
|
140
|
+
|
|
141
|
+
return ToolResult(
|
|
142
|
+
success=True,
|
|
143
|
+
message=f"Successfully found {len(search_results)} results (using BochaAI)",
|
|
144
|
+
content=search_results
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
except Exception as e:
|
|
148
|
+
logger.error(f"BochaAI search failed: {str(e)}")
|
|
149
|
+
return ToolResult(
|
|
150
|
+
success=False,
|
|
151
|
+
message=f"BochaAI search failed: {str(e)}",
|
|
152
|
+
content=traceback.format_exc()
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
def _search_with_metaso(self) -> ToolResult:
|
|
156
|
+
"""Search using Metaso"""
|
|
157
|
+
try:
|
|
158
|
+
# Check if Metaso API key is provided
|
|
159
|
+
api_key = getattr(self.args, 'metaso_api_key', None) or os.getenv('METASO_API_KEY')
|
|
160
|
+
if not api_key:
|
|
161
|
+
return ToolResult(
|
|
162
|
+
success=False,
|
|
163
|
+
message="Metaso API key not provided, please set --metaso_api_key parameter or METASO_API_KEY environment variable",
|
|
164
|
+
content=[]
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
# Initialize Metaso client
|
|
168
|
+
client = MetasoClient(api_key=api_key)
|
|
169
|
+
|
|
170
|
+
# Prepare search parameters
|
|
171
|
+
scope = "webpage" # Default search web pages
|
|
172
|
+
if self.tool.sources:
|
|
173
|
+
# Map sources to Metaso's scope
|
|
174
|
+
sources_list = [s.strip().lower() for s in self.tool.sources.split(',')]
|
|
175
|
+
if "news" in sources_list:
|
|
176
|
+
scope = "news"
|
|
177
|
+
# Metaso does not support images search yet, keep default webpage
|
|
178
|
+
|
|
179
|
+
# Parse scrape_options to get additional parameters
|
|
180
|
+
include_summary = False
|
|
181
|
+
include_raw_content = False
|
|
182
|
+
if self.tool.scrape_options:
|
|
183
|
+
try:
|
|
184
|
+
scrape_opts = json.loads(self.tool.scrape_options)
|
|
185
|
+
include_summary = scrape_opts.get('include_summary', False)
|
|
186
|
+
include_raw_content = scrape_opts.get('include_raw_content', False)
|
|
187
|
+
except json.JSONDecodeError:
|
|
188
|
+
pass
|
|
189
|
+
|
|
190
|
+
# Execute search
|
|
191
|
+
logger.info(f"Performing web search using Metaso, query: {self.tool.query}")
|
|
192
|
+
result = client.search(
|
|
193
|
+
query=self.tool.query,
|
|
194
|
+
scope=scope,
|
|
195
|
+
size=self.tool.limit,
|
|
196
|
+
include_summary=include_summary,
|
|
197
|
+
include_raw_content=include_raw_content
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
if not result.success:
|
|
201
|
+
return ToolResult(
|
|
202
|
+
success=False,
|
|
203
|
+
message=f"Metaso search failed: {result.error}",
|
|
204
|
+
content=[]
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
# Format search results
|
|
208
|
+
search_results = []
|
|
209
|
+
for webpage in result.webpages:
|
|
210
|
+
result_item = {
|
|
211
|
+
"type": "web",
|
|
212
|
+
"title": webpage.title,
|
|
213
|
+
"url": webpage.link,
|
|
214
|
+
"description": webpage.snippet,
|
|
215
|
+
"position": webpage.position,
|
|
216
|
+
"score": webpage.score,
|
|
217
|
+
"provider": "metaso"
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if webpage.date:
|
|
221
|
+
result_item["date"] = webpage.date
|
|
222
|
+
if webpage.authors:
|
|
223
|
+
result_item["authors"] = webpage.authors
|
|
224
|
+
|
|
225
|
+
search_results.append(result_item)
|
|
226
|
+
|
|
227
|
+
return ToolResult(
|
|
228
|
+
success=True,
|
|
229
|
+
message=f"Successfully found {len(search_results)} results (using Metaso)",
|
|
230
|
+
content=search_results
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
except Exception as e:
|
|
234
|
+
logger.error(f"Metaso search failed: {str(e)}")
|
|
235
|
+
return ToolResult(
|
|
236
|
+
success=False,
|
|
237
|
+
message=f"Metaso search failed: {str(e)}",
|
|
238
|
+
content=traceback.format_exc()
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
def _search_with_firecrawl(self) -> ToolResult:
|
|
242
|
+
"""Search using Firecrawl"""
|
|
243
|
+
try:
|
|
244
|
+
# Check if Firecrawl API key is provided
|
|
245
|
+
api_key = getattr(self.args, 'firecrawl_api_key', None) or os.getenv('FIRECRAWL_API_KEY')
|
|
246
|
+
if not api_key:
|
|
247
|
+
return ToolResult(
|
|
248
|
+
success=False,
|
|
249
|
+
message="Firecrawl API key not provided, please set --firecrawl_api_key parameter or FIRECRAWL_API_KEY environment variable",
|
|
250
|
+
content=[]
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
# Import Firecrawl SDK
|
|
254
|
+
try:
|
|
255
|
+
from firecrawl import Firecrawl
|
|
256
|
+
except ImportError:
|
|
257
|
+
return ToolResult(
|
|
258
|
+
success=False,
|
|
259
|
+
message="Firecrawl SDK not installed, please run: pip install firecrawl-py",
|
|
260
|
+
content=[]
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
# Initialize Firecrawl client
|
|
264
|
+
firecrawl = Firecrawl(api_key=api_key)
|
|
265
|
+
|
|
266
|
+
# Prepare search parameters
|
|
267
|
+
search_params = {
|
|
268
|
+
"query": self.tool.query,
|
|
269
|
+
"limit": self.tool.limit
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
# Add optional parameters
|
|
273
|
+
if self.tool.sources:
|
|
274
|
+
# Parse comma-separated sources string
|
|
275
|
+
sources_list = [s.strip() for s in self.tool.sources.split(',') if s.strip()]
|
|
276
|
+
search_params["sources"] = sources_list
|
|
277
|
+
if self.tool.scrape_options:
|
|
278
|
+
# Parse JSON format scrape_options string
|
|
279
|
+
try:
|
|
280
|
+
scrape_options_dict = json.loads(self.tool.scrape_options)
|
|
281
|
+
search_params["scrape_options"] = scrape_options_dict
|
|
282
|
+
except json.JSONDecodeError as e:
|
|
283
|
+
logger.warning(f"scrape_options JSON parsing failed: {e}, ignoring this parameter")
|
|
284
|
+
if self.tool.location:
|
|
285
|
+
search_params["location"] = self.tool.location
|
|
286
|
+
if self.tool.tbs:
|
|
287
|
+
search_params["tbs"] = self.tool.tbs
|
|
288
|
+
|
|
289
|
+
# Execute search
|
|
290
|
+
logger.info(f"Starting web search, query: {self.tool.query}")
|
|
291
|
+
results = firecrawl.search(**search_params)
|
|
292
|
+
|
|
293
|
+
# Check result type and success status
|
|
294
|
+
if not results:
|
|
295
|
+
return ToolResult(
|
|
296
|
+
success=False,
|
|
297
|
+
message="No results returned",
|
|
298
|
+
content=[]
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
# New version firecrawl returns SearchData object with different structure
|
|
302
|
+
if hasattr(results, 'success') and not results.success:
|
|
303
|
+
error_msg = getattr(results, 'error', 'Unknown error')
|
|
304
|
+
return ToolResult(
|
|
305
|
+
success=False,
|
|
306
|
+
message=f"Search failed: {error_msg}",
|
|
307
|
+
content=[]
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
# Format search results
|
|
311
|
+
search_results = []
|
|
312
|
+
# New version firecrawl returned data might be attribute instead of dict key
|
|
313
|
+
if hasattr(results, 'data'):
|
|
314
|
+
data = results.data
|
|
315
|
+
else:
|
|
316
|
+
data = results.get('data', {}) if hasattr(results, 'get') else {}
|
|
317
|
+
|
|
318
|
+
# If data is empty, log information for debugging
|
|
319
|
+
if not data or (isinstance(data, dict) and not data):
|
|
320
|
+
logger.info("Search returned empty data, possibly due to API quota limit or service status issues")
|
|
321
|
+
|
|
322
|
+
# Process web results - new version might be directly in data, not in data.web
|
|
323
|
+
web_results = []
|
|
324
|
+
if hasattr(data, 'web'):
|
|
325
|
+
web_results = data.web
|
|
326
|
+
elif isinstance(data, dict) and 'web' in data:
|
|
327
|
+
web_results = data['web']
|
|
328
|
+
elif isinstance(data, list):
|
|
329
|
+
# Might directly return result list
|
|
330
|
+
web_results = data
|
|
331
|
+
|
|
332
|
+
if web_results:
|
|
333
|
+
for item in web_results:
|
|
334
|
+
# Handle possible object or dictionary format
|
|
335
|
+
title = getattr(item, 'title', None) or (item.get('title', '') if hasattr(item, 'get') else '')
|
|
336
|
+
url = getattr(item, 'url', None) or (item.get('url', '') if hasattr(item, 'get') else '')
|
|
337
|
+
description = getattr(item, 'description', None) or (item.get('description', '') if hasattr(item, 'get') else '')
|
|
338
|
+
position = getattr(item, 'position', None) or (item.get('position', 0) if hasattr(item, 'get') else 0)
|
|
339
|
+
|
|
340
|
+
result_item = {
|
|
341
|
+
"type": "web",
|
|
342
|
+
"title": title,
|
|
343
|
+
"url": url,
|
|
344
|
+
"description": description,
|
|
345
|
+
"position": position
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
# If there is scraped content, add to results
|
|
349
|
+
markdown = getattr(item, 'markdown', None) or (item.get('markdown') if hasattr(item, 'get') else None)
|
|
350
|
+
if markdown:
|
|
351
|
+
result_item['content'] = markdown
|
|
352
|
+
|
|
353
|
+
links = getattr(item, 'links', None) or (item.get('links') if hasattr(item, 'get') else None)
|
|
354
|
+
if links:
|
|
355
|
+
result_item['links'] = links
|
|
356
|
+
|
|
357
|
+
metadata = getattr(item, 'metadata', None) or (item.get('metadata') if hasattr(item, 'get') else None)
|
|
358
|
+
if metadata:
|
|
359
|
+
result_item['metadata'] = metadata
|
|
360
|
+
|
|
361
|
+
search_results.append(result_item)
|
|
362
|
+
|
|
363
|
+
# Process news results
|
|
364
|
+
if 'news' in data:
|
|
365
|
+
for item in data['news']:
|
|
366
|
+
result_item = {
|
|
367
|
+
"type": "news",
|
|
368
|
+
"title": item.get('title', ''),
|
|
369
|
+
"url": item.get('url', ''),
|
|
370
|
+
"snippet": item.get('snippet', ''),
|
|
371
|
+
"date": item.get('date', ''),
|
|
372
|
+
"position": item.get('position', 0)
|
|
373
|
+
}
|
|
374
|
+
search_results.append(result_item)
|
|
375
|
+
|
|
376
|
+
# Process image results
|
|
377
|
+
if 'images' in data:
|
|
378
|
+
for item in data['images']:
|
|
379
|
+
result_item = {
|
|
380
|
+
"type": "image",
|
|
381
|
+
"title": item.get('title', ''),
|
|
382
|
+
"imageUrl": item.get('imageUrl', ''),
|
|
383
|
+
"url": item.get('url', ''),
|
|
384
|
+
"imageWidth": item.get('imageWidth', 0),
|
|
385
|
+
"imageHeight": item.get('imageHeight', 0),
|
|
386
|
+
"position": item.get('position', 0)
|
|
387
|
+
}
|
|
388
|
+
search_results.append(result_item)
|
|
389
|
+
|
|
390
|
+
return ToolResult(
|
|
391
|
+
success=True,
|
|
392
|
+
message=f"Successfully found {len(search_results)} results (using Firecrawl)",
|
|
393
|
+
content=search_results
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
except Exception as e:
|
|
397
|
+
logger.error(f"Firecrawl search failed: {str(e)}")
|
|
398
|
+
return ToolResult(
|
|
399
|
+
success=False,
|
|
400
|
+
message=f"Firecrawl search failed: {str(e)}",
|
|
401
|
+
content=traceback.format_exc()
|
|
402
|
+
)
|
|
403
|
+
|
|
404
|
+
def resolve(self) -> ToolResult:
|
|
405
|
+
"""Implement web search tool resolution logic"""
|
|
406
|
+
try:
|
|
407
|
+
# Determine which provider to use
|
|
408
|
+
arg_bochaai_key = self.args.bochaai_api_key
|
|
409
|
+
bochaai_key = arg_bochaai_key
|
|
410
|
+
|
|
411
|
+
arg_metaso_key = self.args.metaso_api_key
|
|
412
|
+
metaso_key = arg_metaso_key
|
|
413
|
+
|
|
414
|
+
arg_firecrawl_key = self.args.firecrawl_api_key
|
|
415
|
+
firecrawl_key = arg_firecrawl_key
|
|
416
|
+
|
|
417
|
+
# Check if any API key is configured
|
|
418
|
+
if not any([bochaai_key, metaso_key, firecrawl_key]):
|
|
419
|
+
# No API key configured, guide to use search engines and curl
|
|
420
|
+
search_query = self.tool.query.replace(' ', '+')
|
|
421
|
+
|
|
422
|
+
# Build search suggestions
|
|
423
|
+
search_suggestions = []
|
|
424
|
+
search_suggestions.append(f"# Use search engines for web search")
|
|
425
|
+
search_suggestions.append(f"# 1. Google Search:")
|
|
426
|
+
search_suggestions.append(f"# Visit: https://www.google.com/search?q={search_query}")
|
|
427
|
+
search_suggestions.append(f"")
|
|
428
|
+
search_suggestions.append(f"# 2. DuckDuckGo Search:")
|
|
429
|
+
search_suggestions.append(f"# Visit: https://duckduckgo.com/?q={search_query}")
|
|
430
|
+
search_suggestions.append(f"")
|
|
431
|
+
search_suggestions.append(f"# 3. Use curl to get search result pages (need to handle anti-crawling mechanisms):")
|
|
432
|
+
search_suggestions.append(f"curl -s -L -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' 'https://www.google.com/search?q={search_query}'")
|
|
433
|
+
search_suggestions.append(f"")
|
|
434
|
+
search_suggestions.append(f"# 4. If you know specific websites, search them directly:")
|
|
435
|
+
search_suggestions.append(f"curl -s -L 'https://example.com/search?q={search_query}'")
|
|
436
|
+
|
|
437
|
+
if self.tool.sources:
|
|
438
|
+
search_suggestions.append(f"")
|
|
439
|
+
search_suggestions.append(f"# Specified search type: {self.tool.sources}")
|
|
440
|
+
if "news" in self.tool.sources:
|
|
441
|
+
search_suggestions.append(f"# For news search, visit: https://news.google.com/search?q={search_query}")
|
|
442
|
+
if "images" in self.tool.sources:
|
|
443
|
+
search_suggestions.append(f"# For image search, visit: https://www.google.com/search?tbm=isch&q={search_query}")
|
|
444
|
+
|
|
445
|
+
if self.tool.location:
|
|
446
|
+
search_suggestions.append(f"")
|
|
447
|
+
search_suggestions.append(f"# Geographic location restriction: {self.tool.location}")
|
|
448
|
+
search_suggestions.append(f"# You can add location keywords to search")
|
|
449
|
+
|
|
450
|
+
if self.tool.tbs:
|
|
451
|
+
search_suggestions.append(f"")
|
|
452
|
+
search_suggestions.append(f"# Time filter: {self.tool.tbs}")
|
|
453
|
+
search_suggestions.append(f"# Google search can use time filter options in the tools menu")
|
|
454
|
+
|
|
455
|
+
suggestion_text = "\n".join(search_suggestions)
|
|
456
|
+
|
|
457
|
+
return ToolResult(
|
|
458
|
+
success=False,
|
|
459
|
+
message=f"No web search API key configured (BochaAI, Metaso, Firecrawl).",
|
|
460
|
+
content={}
|
|
461
|
+
)
|
|
462
|
+
|
|
463
|
+
# Determine provider priority: BochaAI > Metaso > Firecrawl
|
|
464
|
+
provider = None
|
|
465
|
+
selected_key_name = None
|
|
466
|
+
selected_key_value = None
|
|
467
|
+
if bochaai_key:
|
|
468
|
+
provider = "bochaai"
|
|
469
|
+
selected_key_name = "bochaai_api_key" if arg_bochaai_key else "BOCHAAI_API_KEY"
|
|
470
|
+
selected_key_value = bochaai_key
|
|
471
|
+
elif metaso_key:
|
|
472
|
+
provider = "metaso"
|
|
473
|
+
selected_key_name = "metaso_api_key" if arg_metaso_key else "METASO_API_KEY"
|
|
474
|
+
selected_key_value = metaso_key
|
|
475
|
+
elif firecrawl_key:
|
|
476
|
+
provider = "firecrawl"
|
|
477
|
+
selected_key_name = "firecrawl_api_key" if arg_firecrawl_key else "FIRECRAWL_API_KEY"
|
|
478
|
+
selected_key_value = firecrawl_key
|
|
479
|
+
|
|
480
|
+
key_prefix = (selected_key_value[:10] if selected_key_value else "")
|
|
481
|
+
logger.info(f"Using search provider: {provider}, key_name: {selected_key_name}, key_prefix: {key_prefix}")
|
|
482
|
+
|
|
483
|
+
if provider == "bochaai":
|
|
484
|
+
return self._search_with_bochaai()
|
|
485
|
+
elif provider == "metaso":
|
|
486
|
+
return self._search_with_metaso()
|
|
487
|
+
elif provider == "firecrawl":
|
|
488
|
+
return self._search_with_firecrawl()
|
|
489
|
+
|
|
490
|
+
# This situation should not happen theoretically
|
|
491
|
+
return ToolResult(
|
|
492
|
+
success=False,
|
|
493
|
+
message="Internal error: Unable to determine search provider",
|
|
494
|
+
content=[]
|
|
495
|
+
)
|
|
496
|
+
|
|
497
|
+
except Exception as e:
|
|
498
|
+
logger.error(f"Web search tool execution failed: {str(e)}")
|
|
499
|
+
return ToolResult(
|
|
500
|
+
success=False,
|
|
501
|
+
message=f"Web search tool execution failed: {str(e)}",
|
|
502
|
+
content=traceback.format_exc()
|
|
503
|
+
)
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
class WebSearchToolDescGenerator:
|
|
507
|
+
def __init__(self, params: Dict[str, Any]):
|
|
508
|
+
self.params = params
|
|
509
|
+
|
|
510
|
+
@byzerllm.prompt()
|
|
511
|
+
def web_search_description(self) -> Dict:
|
|
512
|
+
"""
|
|
513
|
+
Description: Request to perform web search using Firecrawl, Metaso or BochaAI API. Use this when you need to search for current web content, news, or images to gather information for completing your task. This tool supports multiple search sources and can optionally scrape the full content of search result pages. You can use web_crawl to fetch the url of the search result pages.
|
|
514
|
+
Parameters:
|
|
515
|
+
- query: (required) The search query string to search for
|
|
516
|
+
- limit: (optional) Maximum number of results to return (default: 5)
|
|
517
|
+
- sources: (optional) Comma-separated search source types, e.g., "web", "news", "images", "web,news"
|
|
518
|
+
- scrape_options: (optional) Additional scraping options as JSON string, e.g., '{"formats": ["markdown"], "include_summary": true, "include_sites": "example.com", "exclude_sites": "bad.com"}'
|
|
519
|
+
- location: (optional) Geographic location to focus the search (Firecrawl only)
|
|
520
|
+
- tbs: (optional) Time-based search parameters for filtering results (Firecrawl/BochaAI)
|
|
521
|
+
Usage:
|
|
522
|
+
<web_search>
|
|
523
|
+
<query>Your search query here</query>
|
|
524
|
+
<limit>5</limit>
|
|
525
|
+
<sources>web</sources>
|
|
526
|
+
</web_search>
|
|
527
|
+
"""
|
|
528
|
+
return self.params
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
def register_web_search_tool():
|
|
532
|
+
"""Register web search tool"""
|
|
533
|
+
desc_gen = WebSearchToolDescGenerator({})
|
|
534
|
+
|
|
535
|
+
# 准备工具描述
|
|
536
|
+
description = ToolDescription(
|
|
537
|
+
description=desc_gen.web_search_description.prompt()
|
|
538
|
+
)
|
|
539
|
+
|
|
540
|
+
# 准备工具示例
|
|
541
|
+
example = ToolExample(
|
|
542
|
+
title="Web search tool usage example",
|
|
543
|
+
body="""<web_search>
|
|
544
|
+
<query>Python RAG system implementation</query>
|
|
545
|
+
<limit>3</limit>
|
|
546
|
+
<sources>web</sources>
|
|
547
|
+
</web_search>"""
|
|
548
|
+
)
|
|
549
|
+
|
|
550
|
+
# 注册工具
|
|
551
|
+
ToolRegistry.register_tool(
|
|
552
|
+
tool_tag="web_search", # XML标签名
|
|
553
|
+
tool_cls=WebSearchTool, # 工具类
|
|
554
|
+
resolver_cls=WebSearchToolResolver, # 解析器类
|
|
555
|
+
description=description, # 工具描述
|
|
556
|
+
example=example, # 工具示例
|
|
557
|
+
use_guideline="Use this tool to search for web content across different sources (web pages, news, images). It can optionally scrape complete content from search results. Ideal for gathering current information from the internet to help complete tasks that require up-to-date data." # 使用指南
|
|
558
|
+
)
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Web 工具使用示例
|
|
4
|
+
|
|
5
|
+
这个文件展示了如何使用 WebSearchTool 和 WebCrawlTool 进行网页搜索和爬取。
|
|
6
|
+
注意:需要设置 FIRECRAWL_API_KEY 环境变量或在启动服务时使用 --firecrawl_api_key 参数。
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
def web_search_example():
|
|
10
|
+
"""
|
|
11
|
+
网页搜索工具使用示例
|
|
12
|
+
|
|
13
|
+
在 Agent 对话中可以这样使用:
|
|
14
|
+
"""
|
|
15
|
+
example_xml = """
|
|
16
|
+
<web_search>
|
|
17
|
+
<query>Python RAG系统实现最佳实践</query>
|
|
18
|
+
<limit>5</limit>
|
|
19
|
+
<sources>["web"]</sources>
|
|
20
|
+
</web_search>
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
print("Web Search Tool 使用示例:")
|
|
24
|
+
print(example_xml)
|
|
25
|
+
print()
|
|
26
|
+
|
|
27
|
+
# 搜索新闻的示例
|
|
28
|
+
news_example = """
|
|
29
|
+
<web_search>
|
|
30
|
+
<query>人工智能最新发展</query>
|
|
31
|
+
<limit>3</limit>
|
|
32
|
+
<sources>["news"]</sources>
|
|
33
|
+
<location>China</location>
|
|
34
|
+
<tbs>qdr:d</tbs>
|
|
35
|
+
</web_search>
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
print("搜索新闻示例:")
|
|
39
|
+
print(news_example)
|
|
40
|
+
print()
|
|
41
|
+
|
|
42
|
+
# 搜索图片的示例
|
|
43
|
+
image_example = """
|
|
44
|
+
<web_search>
|
|
45
|
+
<query>机器学习架构图 imagesize:1920x1080</query>
|
|
46
|
+
<limit>5</limit>
|
|
47
|
+
<sources>["images"]</sources>
|
|
48
|
+
</web_search>
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
print("搜索图片示例:")
|
|
52
|
+
print(image_example)
|
|
53
|
+
print()
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def web_crawl_example():
|
|
57
|
+
"""
|
|
58
|
+
网页爬取工具使用示例
|
|
59
|
+
|
|
60
|
+
在 Agent 对话中可以这样使用:
|
|
61
|
+
"""
|
|
62
|
+
example_xml = """
|
|
63
|
+
<web_crawl>
|
|
64
|
+
<url>https://docs.python.org/3/tutorial/</url>
|
|
65
|
+
<limit>10</limit>
|
|
66
|
+
<scrape_options>{"formats": ["markdown", "links"]}</scrape_options>
|
|
67
|
+
<max_depth>2</max_depth>
|
|
68
|
+
</web_crawl>
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
print("Web Crawl Tool 使用示例:")
|
|
72
|
+
print(example_xml)
|
|
73
|
+
print()
|
|
74
|
+
|
|
75
|
+
# 爬取特定路径的示例
|
|
76
|
+
specific_paths_example = """
|
|
77
|
+
<web_crawl>
|
|
78
|
+
<url>https://example.com</url>
|
|
79
|
+
<limit>5</limit>
|
|
80
|
+
<include_paths>["/docs/", "/api/"]</include_paths>
|
|
81
|
+
<exclude_paths>["/admin/", "/private/"]</exclude_paths>
|
|
82
|
+
</web_crawl>
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
print("爬取特定路径示例:")
|
|
86
|
+
print(specific_paths_example)
|
|
87
|
+
print()
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def setup_instructions():
|
|
91
|
+
"""
|
|
92
|
+
设置说明
|
|
93
|
+
"""
|
|
94
|
+
print("=== Firecrawl Web 工具设置说明 ===")
|
|
95
|
+
print()
|
|
96
|
+
print("1. 安装 Firecrawl SDK:")
|
|
97
|
+
print(" pip install firecrawl-py")
|
|
98
|
+
print()
|
|
99
|
+
print("2. 获取 Firecrawl API Key:")
|
|
100
|
+
print(" - 访问 https://firecrawl.dev/ 注册账号")
|
|
101
|
+
print(" - 获取 API Key")
|
|
102
|
+
print()
|
|
103
|
+
print("3. 配置 API Key:")
|
|
104
|
+
print(" 方式 1: 设置环境变量")
|
|
105
|
+
print(" export FIRECRAWL_API_KEY=your_api_key_here")
|
|
106
|
+
print()
|
|
107
|
+
print(" 方式 2: 启动服务时指定参数")
|
|
108
|
+
print(" auto-coder.rag serve --firecrawl_api_key your_api_key_here")
|
|
109
|
+
print()
|
|
110
|
+
print("4. 工具功能说明:")
|
|
111
|
+
print(" - WebSearchTool: 搜索网页、新闻、图片")
|
|
112
|
+
print(" - WebCrawlTool: 深度爬取网站内容")
|
|
113
|
+
print()
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
if __name__ == "__main__":
|
|
117
|
+
setup_instructions()
|
|
118
|
+
web_search_example()
|
|
119
|
+
web_crawl_example()
|