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