auto-coder 1.0.0__py3-none-any.whl → 2.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of auto-coder might be problematic. Click here for more details.
- auto_coder-2.0.0.dist-info/LICENSE +158 -0
- auto_coder-2.0.0.dist-info/METADATA +558 -0
- auto_coder-2.0.0.dist-info/RECORD +795 -0
- {auto_coder-1.0.0.dist-info → auto_coder-2.0.0.dist-info}/WHEEL +1 -1
- {auto_coder-1.0.0.dist-info → auto_coder-2.0.0.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 +73 -59
- autocoder/auto_coder.py +31 -40
- autocoder/auto_coder_rag.py +11 -1084
- autocoder/auto_coder_runner.py +970 -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 +401 -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 +288 -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 +349 -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 +1051 -0
- autocoder/default_project/__init__.py +501 -0
- autocoder/dispacher/__init__.py +4 -12
- autocoder/dispacher/actions/action.py +165 -7
- autocoder/dispacher/actions/plugins/action_regex_project.py +2 -2
- autocoder/index/entry.py +116 -124
- 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 +932 -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 +489 -0
- autocoder/workflow_agents/loader.py +737 -0
- autocoder/workflow_agents/runner.py +267 -0
- autocoder/workflow_agents/types.py +172 -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.0.dist-info}/top_level.txt +0 -0
- /autocoder/{sdk/example.py → common/agent_query_queue/__init__.py} +0 -0
|
@@ -0,0 +1,545 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Comprehensive test suite for the agents module.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
import tempfile
|
|
7
|
+
import shutil
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from unittest.mock import patch, MagicMock
|
|
10
|
+
|
|
11
|
+
from autocoder.common.agents import AgentManager, AgentParser, Agent
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# Test data for agent definitions
|
|
15
|
+
VALID_AGENT_CONTENT = """---
|
|
16
|
+
name: test-agent
|
|
17
|
+
description: A test agent for validation
|
|
18
|
+
tools: read_file, write_to_file, execute_command
|
|
19
|
+
model: gpt-4
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
You are a test agent designed to help with testing scenarios.
|
|
23
|
+
Your task is to assist users with their testing needs.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
MINIMAL_AGENT_CONTENT = """---
|
|
27
|
+
name: minimal-agent
|
|
28
|
+
description: Minimal agent with required fields only
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
You are a minimal agent with only the required fields.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
WILDCARD_TOOLS_AGENT_CONTENT = """---
|
|
35
|
+
name: wildcard-agent
|
|
36
|
+
description: Agent with wildcard tools
|
|
37
|
+
tools: *
|
|
38
|
+
model: gpt-4
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
You are an agent with access to all tools.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
INCLUDE_RULES_AGENT_CONTENT = """---
|
|
45
|
+
name: rules-agent
|
|
46
|
+
description: Agent with include_rules enabled
|
|
47
|
+
tools: read_file, write_to_file
|
|
48
|
+
model: gpt-4
|
|
49
|
+
include_rules: true
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
You are an agent that includes rules in processing.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
INVALID_AGENT_NO_FRONTMATTER = """
|
|
56
|
+
This is just content without frontmatter.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
INVALID_AGENT_NO_NAME = """---
|
|
60
|
+
description: Agent without name
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
Agent content here.
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
INVALID_AGENT_YAML_ERROR = """---
|
|
67
|
+
name: invalid-yaml
|
|
68
|
+
description: Agent with invalid YAML
|
|
69
|
+
tools: [unclosed list
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
Agent content here.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class TestAgent:
|
|
77
|
+
"""Test cases for the Agent dataclass."""
|
|
78
|
+
|
|
79
|
+
def test_agent_creation(self):
|
|
80
|
+
"""Test creating an agent with all fields."""
|
|
81
|
+
agent = Agent(
|
|
82
|
+
name="test-agent",
|
|
83
|
+
description="Test description",
|
|
84
|
+
tools=["read_file", "write_to_file"],
|
|
85
|
+
model="gpt-4",
|
|
86
|
+
content="Test content",
|
|
87
|
+
file_path=Path("/test/path.md"),
|
|
88
|
+
include_rules=True
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
assert agent.name == "test-agent"
|
|
92
|
+
assert agent.description == "Test description"
|
|
93
|
+
assert agent.tools == ["read_file", "write_to_file"]
|
|
94
|
+
assert agent.model == "gpt-4"
|
|
95
|
+
assert agent.content == "Test content"
|
|
96
|
+
assert agent.file_path == Path("/test/path.md")
|
|
97
|
+
assert agent.include_rules == True
|
|
98
|
+
|
|
99
|
+
def test_agent_defaults(self):
|
|
100
|
+
"""Test agent with default values."""
|
|
101
|
+
agent = Agent(name="test", description="desc")
|
|
102
|
+
|
|
103
|
+
assert agent.tools == []
|
|
104
|
+
assert agent.model is None
|
|
105
|
+
assert agent.content == ""
|
|
106
|
+
assert agent.file_path is None
|
|
107
|
+
assert agent.include_rules == False
|
|
108
|
+
|
|
109
|
+
def test_agent_to_dict(self):
|
|
110
|
+
"""Test converting agent to dictionary."""
|
|
111
|
+
agent = Agent(
|
|
112
|
+
name="test-agent",
|
|
113
|
+
description="Test description",
|
|
114
|
+
tools=["read_file", "write_to_file"],
|
|
115
|
+
model="gpt-4",
|
|
116
|
+
content="Test content",
|
|
117
|
+
file_path=Path("/test/path.md"),
|
|
118
|
+
include_rules=True
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
expected = {
|
|
122
|
+
'name': 'test-agent',
|
|
123
|
+
'description': 'Test description',
|
|
124
|
+
'tools': ['read_file', 'write_to_file'],
|
|
125
|
+
'model': 'gpt-4',
|
|
126
|
+
'content': 'Test content',
|
|
127
|
+
'file_path': '/test/path.md',
|
|
128
|
+
'include_rules': True
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
assert agent.to_dict() == expected
|
|
132
|
+
|
|
133
|
+
def test_agent_to_dict_with_none_path(self):
|
|
134
|
+
"""Test converting agent to dictionary with None file_path."""
|
|
135
|
+
agent = Agent(name="test", description="desc")
|
|
136
|
+
result = agent.to_dict()
|
|
137
|
+
|
|
138
|
+
assert result['file_path'] is None
|
|
139
|
+
assert result['include_rules'] == False
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class TestAgentParser:
|
|
143
|
+
"""Test cases for the AgentParser class."""
|
|
144
|
+
|
|
145
|
+
def test_parse_valid_agent_content(self):
|
|
146
|
+
"""Test parsing valid agent content."""
|
|
147
|
+
agent = AgentParser.parse_agent_content(VALID_AGENT_CONTENT)
|
|
148
|
+
|
|
149
|
+
assert agent.name == "test-agent"
|
|
150
|
+
assert agent.description == "A test agent for validation"
|
|
151
|
+
assert agent.tools == ["read_file", "write_to_file", "execute_command"]
|
|
152
|
+
assert agent.model == "gpt-4"
|
|
153
|
+
assert "You are a test agent" in agent.content
|
|
154
|
+
assert agent.file_path is None
|
|
155
|
+
|
|
156
|
+
def test_parse_minimal_agent_content(self):
|
|
157
|
+
"""Test parsing agent with minimal required fields."""
|
|
158
|
+
agent = AgentParser.parse_agent_content(MINIMAL_AGENT_CONTENT)
|
|
159
|
+
|
|
160
|
+
assert agent.name == "minimal-agent"
|
|
161
|
+
assert agent.description == "Minimal agent with required fields only"
|
|
162
|
+
assert agent.tools == []
|
|
163
|
+
assert agent.model is None
|
|
164
|
+
assert agent.include_rules == False # default value when not specified
|
|
165
|
+
assert "You are a minimal agent" in agent.content
|
|
166
|
+
|
|
167
|
+
def test_parse_wildcard_tools_agent_content(self):
|
|
168
|
+
"""Test parsing agent with wildcard tools."""
|
|
169
|
+
agent = AgentParser.parse_agent_content(WILDCARD_TOOLS_AGENT_CONTENT)
|
|
170
|
+
|
|
171
|
+
assert agent.name == "wildcard-agent"
|
|
172
|
+
assert agent.description == "Agent with wildcard tools"
|
|
173
|
+
assert agent.tools == ["*"]
|
|
174
|
+
assert agent.model == "gpt-4"
|
|
175
|
+
assert agent.include_rules == False # default value
|
|
176
|
+
assert "You are an agent with access to all tools" in agent.content
|
|
177
|
+
|
|
178
|
+
def test_parse_include_rules_agent_content(self):
|
|
179
|
+
"""Test parsing agent with include_rules enabled."""
|
|
180
|
+
agent = AgentParser.parse_agent_content(INCLUDE_RULES_AGENT_CONTENT)
|
|
181
|
+
|
|
182
|
+
assert agent.name == "rules-agent"
|
|
183
|
+
assert agent.description == "Agent with include_rules enabled"
|
|
184
|
+
assert agent.tools == ["read_file", "write_to_file"]
|
|
185
|
+
assert agent.model == "gpt-4"
|
|
186
|
+
assert agent.include_rules == True
|
|
187
|
+
assert "You are an agent that includes rules" in agent.content
|
|
188
|
+
|
|
189
|
+
def test_parse_invalid_no_frontmatter(self):
|
|
190
|
+
"""Test parsing content without frontmatter."""
|
|
191
|
+
with pytest.raises(ValueError, match="Invalid agent file format"):
|
|
192
|
+
AgentParser.parse_agent_content(INVALID_AGENT_NO_FRONTMATTER)
|
|
193
|
+
|
|
194
|
+
def test_parse_invalid_no_name(self):
|
|
195
|
+
"""Test parsing agent without name field."""
|
|
196
|
+
with pytest.raises(ValueError, match="Agent definition must include 'name' field"):
|
|
197
|
+
AgentParser.parse_agent_content(INVALID_AGENT_NO_NAME)
|
|
198
|
+
|
|
199
|
+
def test_parse_invalid_yaml(self):
|
|
200
|
+
"""Test parsing agent with invalid YAML."""
|
|
201
|
+
with pytest.raises(ValueError, match="Failed to parse YAML frontmatter"):
|
|
202
|
+
AgentParser.parse_agent_content(INVALID_AGENT_YAML_ERROR)
|
|
203
|
+
|
|
204
|
+
def test_parse_tools_empty(self):
|
|
205
|
+
"""Test parsing empty tools string."""
|
|
206
|
+
assert AgentParser._parse_tools("") == []
|
|
207
|
+
assert AgentParser._parse_tools(" ") == []
|
|
208
|
+
|
|
209
|
+
def test_parse_tools_single(self):
|
|
210
|
+
"""Test parsing single tool."""
|
|
211
|
+
assert AgentParser._parse_tools("Read") == ["Read"]
|
|
212
|
+
assert AgentParser._parse_tools(" Read ") == ["Read"]
|
|
213
|
+
|
|
214
|
+
def test_parse_tools_multiple(self):
|
|
215
|
+
"""Test parsing multiple tools."""
|
|
216
|
+
assert AgentParser._parse_tools("Read, Write, Bash") == ["Read", "Write", "Bash"]
|
|
217
|
+
assert AgentParser._parse_tools("Read,Write,Bash") == ["Read", "Write", "Bash"]
|
|
218
|
+
assert AgentParser._parse_tools(" Read , Write , Bash ") == ["Read", "Write", "Bash"]
|
|
219
|
+
|
|
220
|
+
def test_parse_agent_file_not_found(self):
|
|
221
|
+
"""Test parsing non-existent file."""
|
|
222
|
+
with pytest.raises(ValueError, match="Agent file not found"):
|
|
223
|
+
AgentParser.parse_agent_file(Path("/non/existent/file.md"))
|
|
224
|
+
|
|
225
|
+
def test_parse_agent_file_valid(self):
|
|
226
|
+
"""Test parsing valid agent file."""
|
|
227
|
+
with tempfile.NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
|
|
228
|
+
f.write(VALID_AGENT_CONTENT)
|
|
229
|
+
temp_path = Path(f.name)
|
|
230
|
+
|
|
231
|
+
try:
|
|
232
|
+
agent = AgentParser.parse_agent_file(temp_path)
|
|
233
|
+
assert agent.name == "test-agent"
|
|
234
|
+
assert agent.file_path == temp_path
|
|
235
|
+
finally:
|
|
236
|
+
temp_path.unlink()
|
|
237
|
+
|
|
238
|
+
def test_validate_agent_valid(self):
|
|
239
|
+
"""Test validating a valid agent."""
|
|
240
|
+
agent = Agent(
|
|
241
|
+
name="test-agent",
|
|
242
|
+
description="Test description",
|
|
243
|
+
tools=["read_file", "write_to_file"],
|
|
244
|
+
content="Test content"
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
errors = AgentParser.validate_agent(agent)
|
|
248
|
+
assert errors == []
|
|
249
|
+
|
|
250
|
+
def test_validate_agent_missing_name(self):
|
|
251
|
+
"""Test validating agent without name."""
|
|
252
|
+
agent = Agent(name="", description="desc", content="content")
|
|
253
|
+
errors = AgentParser.validate_agent(agent)
|
|
254
|
+
assert "Agent name is required" in errors
|
|
255
|
+
|
|
256
|
+
def test_validate_agent_missing_description(self):
|
|
257
|
+
"""Test validating agent without description."""
|
|
258
|
+
agent = Agent(name="test", description="", content="content")
|
|
259
|
+
errors = AgentParser.validate_agent(agent)
|
|
260
|
+
assert "Agent description is required" in errors
|
|
261
|
+
|
|
262
|
+
def test_validate_agent_missing_content(self):
|
|
263
|
+
"""Test validating agent without content."""
|
|
264
|
+
agent = Agent(name="test", description="desc", content="")
|
|
265
|
+
errors = AgentParser.validate_agent(agent)
|
|
266
|
+
assert "Agent content (system prompt) is required" in errors
|
|
267
|
+
|
|
268
|
+
def test_validate_agent_invalid_tools(self):
|
|
269
|
+
"""Test validating agent with invalid tools."""
|
|
270
|
+
agent = Agent(
|
|
271
|
+
name="test",
|
|
272
|
+
description="desc",
|
|
273
|
+
content="content",
|
|
274
|
+
tools=["read_file", "InvalidTool", "write_to_file"]
|
|
275
|
+
)
|
|
276
|
+
errors = AgentParser.validate_agent(agent)
|
|
277
|
+
assert any("Unknown tool: InvalidTool" in error for error in errors)
|
|
278
|
+
|
|
279
|
+
def test_validate_agent_wildcard_tools(self):
|
|
280
|
+
"""Test validating agent with wildcard tools."""
|
|
281
|
+
agent = Agent(
|
|
282
|
+
name="test",
|
|
283
|
+
description="desc",
|
|
284
|
+
content="content",
|
|
285
|
+
tools=["*"]
|
|
286
|
+
)
|
|
287
|
+
errors = AgentParser.validate_agent(agent)
|
|
288
|
+
assert errors == [] # "*" should be valid
|
|
289
|
+
|
|
290
|
+
def test_validate_agent_multiple_errors(self):
|
|
291
|
+
"""Test validating agent with multiple errors."""
|
|
292
|
+
agent = Agent(
|
|
293
|
+
name="",
|
|
294
|
+
description="",
|
|
295
|
+
content="",
|
|
296
|
+
tools=["InvalidTool"]
|
|
297
|
+
)
|
|
298
|
+
errors = AgentParser.validate_agent(agent)
|
|
299
|
+
assert len(errors) == 4 # name, description, content, tool
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
class TestAgentManager:
|
|
303
|
+
"""Test cases for the AgentManager class."""
|
|
304
|
+
|
|
305
|
+
@pytest.fixture
|
|
306
|
+
def temp_project(self):
|
|
307
|
+
"""Create a temporary project directory."""
|
|
308
|
+
temp_dir = tempfile.mkdtemp()
|
|
309
|
+
yield Path(temp_dir)
|
|
310
|
+
shutil.rmtree(temp_dir)
|
|
311
|
+
|
|
312
|
+
@pytest.fixture
|
|
313
|
+
def agents_dir(self, temp_project):
|
|
314
|
+
"""Create agents directory with test files."""
|
|
315
|
+
agents_dir = temp_project / ".autocoderagents"
|
|
316
|
+
agents_dir.mkdir()
|
|
317
|
+
|
|
318
|
+
# Create test agent files
|
|
319
|
+
(agents_dir / "test-agent.md").write_text(VALID_AGENT_CONTENT)
|
|
320
|
+
(agents_dir / "minimal-agent.md").write_text(MINIMAL_AGENT_CONTENT)
|
|
321
|
+
|
|
322
|
+
return agents_dir
|
|
323
|
+
|
|
324
|
+
def test_agent_manager_initialization(self, temp_project):
|
|
325
|
+
"""Test AgentManager initialization."""
|
|
326
|
+
manager = AgentManager(str(temp_project))
|
|
327
|
+
assert manager.project_root == temp_project
|
|
328
|
+
assert isinstance(manager.agents, dict)
|
|
329
|
+
|
|
330
|
+
def test_load_agents_from_directory(self, temp_project, agents_dir):
|
|
331
|
+
"""Test loading agents from directory."""
|
|
332
|
+
with patch.object(AgentManager, '_load_agents') as mock_load:
|
|
333
|
+
manager = AgentManager(str(temp_project))
|
|
334
|
+
mock_load.reset_mock() # Reset the mock after __init__
|
|
335
|
+
|
|
336
|
+
# Manually test the loading method
|
|
337
|
+
manager._load_agents_from_directory(agents_dir)
|
|
338
|
+
|
|
339
|
+
assert len(manager.agents) == 2
|
|
340
|
+
assert "test-agent" in manager.agents
|
|
341
|
+
assert "minimal-agent" in manager.agents
|
|
342
|
+
|
|
343
|
+
def test_get_agent_existing(self, temp_project, agents_dir):
|
|
344
|
+
"""Test getting an existing agent."""
|
|
345
|
+
manager = AgentManager(str(temp_project))
|
|
346
|
+
manager._load_agents_from_directory(agents_dir)
|
|
347
|
+
|
|
348
|
+
agent = manager.get_agent("test-agent")
|
|
349
|
+
assert agent is not None
|
|
350
|
+
assert agent.name == "test-agent"
|
|
351
|
+
|
|
352
|
+
def test_get_agent_non_existing(self, temp_project):
|
|
353
|
+
"""Test getting a non-existing agent."""
|
|
354
|
+
manager = AgentManager(str(temp_project))
|
|
355
|
+
agent = manager.get_agent("non-existing")
|
|
356
|
+
assert agent is None
|
|
357
|
+
|
|
358
|
+
def test_list_agents(self, temp_project, agents_dir):
|
|
359
|
+
"""Test listing all agents."""
|
|
360
|
+
manager = AgentManager(str(temp_project))
|
|
361
|
+
manager._load_agents_from_directory(agents_dir)
|
|
362
|
+
|
|
363
|
+
agents = manager.list_agents()
|
|
364
|
+
assert len(agents) == 2
|
|
365
|
+
agent_names = [agent.name for agent in agents]
|
|
366
|
+
assert "test-agent" in agent_names
|
|
367
|
+
assert "minimal-agent" in agent_names
|
|
368
|
+
|
|
369
|
+
def test_get_agent_names(self, temp_project, agents_dir):
|
|
370
|
+
"""Test getting agent names."""
|
|
371
|
+
manager = AgentManager(str(temp_project))
|
|
372
|
+
manager._load_agents_from_directory(agents_dir)
|
|
373
|
+
|
|
374
|
+
names = manager.get_agent_names()
|
|
375
|
+
assert len(names) == 2
|
|
376
|
+
assert "test-agent" in names
|
|
377
|
+
assert "minimal-agent" in names
|
|
378
|
+
|
|
379
|
+
def test_reload_agents(self, temp_project, agents_dir):
|
|
380
|
+
"""Test reloading agents."""
|
|
381
|
+
manager = AgentManager(str(temp_project))
|
|
382
|
+
manager._load_agents_from_directory(agents_dir)
|
|
383
|
+
|
|
384
|
+
# Add a new agent file
|
|
385
|
+
new_agent_content = """---
|
|
386
|
+
name: new-agent
|
|
387
|
+
description: Newly added agent
|
|
388
|
+
---
|
|
389
|
+
New agent content.
|
|
390
|
+
"""
|
|
391
|
+
(agents_dir / "new-agent.md").write_text(new_agent_content)
|
|
392
|
+
|
|
393
|
+
# Mock the _load_agents method to use our test directory
|
|
394
|
+
with patch.object(manager, '_load_agents') as mock_load:
|
|
395
|
+
mock_load.side_effect = lambda: manager._load_agents_from_directory(agents_dir)
|
|
396
|
+
manager.reload_agents()
|
|
397
|
+
mock_load.assert_called_once()
|
|
398
|
+
|
|
399
|
+
def test_render_sub_agents_section_no_agents(self, temp_project):
|
|
400
|
+
"""Test rendering sub agents section when no agents are loaded."""
|
|
401
|
+
manager = AgentManager(str(temp_project))
|
|
402
|
+
result = manager.render_sub_agents_section()
|
|
403
|
+
# The method returns a rendered template string, so we check if it's empty or minimal
|
|
404
|
+
assert isinstance(result, str)
|
|
405
|
+
# For no agents, the template should render to empty or minimal content
|
|
406
|
+
assert len(result.strip()) == 0 or "Available Sub Agents" not in result
|
|
407
|
+
|
|
408
|
+
def test_render_sub_agents_section_with_agents(self, temp_project, agents_dir):
|
|
409
|
+
"""Test rendering sub agents section with loaded agents."""
|
|
410
|
+
manager = AgentManager(str(temp_project))
|
|
411
|
+
manager._load_agents_from_directory(agents_dir)
|
|
412
|
+
|
|
413
|
+
result = manager.render_sub_agents_section(current_model="gpt-4")
|
|
414
|
+
# The method returns a rendered template string
|
|
415
|
+
assert isinstance(result, str)
|
|
416
|
+
# Check that the rendered template contains expected content
|
|
417
|
+
assert "Available Named Sub Agents" in result
|
|
418
|
+
assert "test-agent" in result
|
|
419
|
+
assert "minimal-agent" in result
|
|
420
|
+
assert "run_named_subagents" in result
|
|
421
|
+
|
|
422
|
+
def test_render_sub_agents_section_no_model(self, temp_project, agents_dir):
|
|
423
|
+
"""Test rendering sub agents section without model raises error."""
|
|
424
|
+
manager = AgentManager(str(temp_project))
|
|
425
|
+
# Create agent without model
|
|
426
|
+
agent_content = """---
|
|
427
|
+
name: no-model-agent
|
|
428
|
+
description: Agent without model
|
|
429
|
+
---
|
|
430
|
+
Agent content.
|
|
431
|
+
"""
|
|
432
|
+
(agents_dir / "no-model.md").write_text(agent_content)
|
|
433
|
+
manager._load_agents_from_directory(agents_dir)
|
|
434
|
+
|
|
435
|
+
with pytest.raises(ValueError, match="has no model specified"):
|
|
436
|
+
manager.render_sub_agents_section()
|
|
437
|
+
|
|
438
|
+
def test_to_dict(self, temp_project, agents_dir):
|
|
439
|
+
"""Test converting manager to dictionary."""
|
|
440
|
+
manager = AgentManager(str(temp_project))
|
|
441
|
+
manager._load_agents_from_directory(agents_dir)
|
|
442
|
+
|
|
443
|
+
result = manager.to_dict()
|
|
444
|
+
assert "project_root" in result
|
|
445
|
+
assert "search_paths" in result
|
|
446
|
+
assert "agents" in result
|
|
447
|
+
assert len(result["agents"]) == 2
|
|
448
|
+
|
|
449
|
+
def test_agent_priority_override(self, temp_project):
|
|
450
|
+
"""Test that higher priority agents override lower priority ones."""
|
|
451
|
+
# Create agents in different priority directories
|
|
452
|
+
high_priority_dir = temp_project / ".autocoderagents"
|
|
453
|
+
low_priority_dir = temp_project / ".auto-coder" / ".autocoderagents"
|
|
454
|
+
|
|
455
|
+
high_priority_dir.mkdir()
|
|
456
|
+
low_priority_dir.mkdir(parents=True)
|
|
457
|
+
|
|
458
|
+
# Same agent name in both directories
|
|
459
|
+
agent_low = """---
|
|
460
|
+
name: conflict-agent
|
|
461
|
+
description: Low priority agent
|
|
462
|
+
---
|
|
463
|
+
Low priority content.
|
|
464
|
+
"""
|
|
465
|
+
agent_high = """---
|
|
466
|
+
name: conflict-agent
|
|
467
|
+
description: High priority agent
|
|
468
|
+
---
|
|
469
|
+
High priority content.
|
|
470
|
+
"""
|
|
471
|
+
|
|
472
|
+
(low_priority_dir / "conflict.md").write_text(agent_low)
|
|
473
|
+
(high_priority_dir / "conflict.md").write_text(agent_high)
|
|
474
|
+
|
|
475
|
+
manager = AgentManager(str(temp_project))
|
|
476
|
+
|
|
477
|
+
# Test fallback loading to simulate the behavior
|
|
478
|
+
manager._load_agents_fallback()
|
|
479
|
+
|
|
480
|
+
# High priority should win
|
|
481
|
+
agent = manager.get_agent("conflict-agent")
|
|
482
|
+
assert agent is not None
|
|
483
|
+
assert agent.description == "High priority agent"
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
@pytest.mark.integration
|
|
487
|
+
class TestAgentManagerIntegration:
|
|
488
|
+
"""Integration tests for AgentManager with priority directory finder."""
|
|
489
|
+
|
|
490
|
+
@pytest.fixture
|
|
491
|
+
def complex_project(self):
|
|
492
|
+
"""Create a complex project with multiple agent directories."""
|
|
493
|
+
temp_dir = tempfile.mkdtemp()
|
|
494
|
+
project_root = Path(temp_dir)
|
|
495
|
+
|
|
496
|
+
# Create different priority directories
|
|
497
|
+
project_agents = project_root / ".autocoderagents"
|
|
498
|
+
autocoder_agents = project_root / ".auto-coder" / ".autocoderagents"
|
|
499
|
+
|
|
500
|
+
project_agents.mkdir()
|
|
501
|
+
autocoder_agents.mkdir(parents=True)
|
|
502
|
+
|
|
503
|
+
# Add agents to each directory
|
|
504
|
+
project_agent = """---
|
|
505
|
+
name: project-agent
|
|
506
|
+
description: Project level agent
|
|
507
|
+
---
|
|
508
|
+
Project level agent content.
|
|
509
|
+
"""
|
|
510
|
+
autocoder_agent = """---
|
|
511
|
+
name: autocoder-agent
|
|
512
|
+
description: Auto-coder level agent
|
|
513
|
+
---
|
|
514
|
+
Auto-coder level agent content.
|
|
515
|
+
"""
|
|
516
|
+
|
|
517
|
+
(project_agents / "project.md").write_text(project_agent)
|
|
518
|
+
(autocoder_agents / "autocoder.md").write_text(autocoder_agent)
|
|
519
|
+
|
|
520
|
+
yield project_root
|
|
521
|
+
shutil.rmtree(temp_dir)
|
|
522
|
+
|
|
523
|
+
@patch('autocoder.common.agents.agent_manager.PriorityDirectoryFinder')
|
|
524
|
+
def test_priority_finder_integration(self, mock_finder_class, complex_project):
|
|
525
|
+
"""Test integration with priority directory finder."""
|
|
526
|
+
# Mock the finder to return successful result
|
|
527
|
+
mock_finder = MagicMock()
|
|
528
|
+
mock_result = MagicMock()
|
|
529
|
+
mock_result.success = True
|
|
530
|
+
mock_result.primary_directory = str(complex_project / ".autocoderagents")
|
|
531
|
+
mock_finder.find_directories.return_value = mock_result
|
|
532
|
+
mock_finder_class.return_value = mock_finder
|
|
533
|
+
|
|
534
|
+
manager = AgentManager(str(complex_project))
|
|
535
|
+
|
|
536
|
+
# Verify finder was called with correct config
|
|
537
|
+
assert mock_finder_class.called
|
|
538
|
+
assert mock_finder.find_directories.called
|
|
539
|
+
|
|
540
|
+
# Should load from the primary directory
|
|
541
|
+
assert "project-agent" in manager.agents
|
|
542
|
+
|
|
543
|
+
|
|
544
|
+
if __name__ == "__main__":
|
|
545
|
+
pytest.main([__file__, "-v"])
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Utility functions for handling async/sync conversions consistently.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import concurrent.futures
|
|
7
|
+
from typing import TypeVar, Callable, Awaitable, Any
|
|
8
|
+
from functools import wraps
|
|
9
|
+
|
|
10
|
+
T = TypeVar('T')
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def run_async_in_sync(async_func: Callable[..., Awaitable[T]], *args, **kwargs) -> T:
|
|
14
|
+
"""
|
|
15
|
+
Run an async function in a synchronous context.
|
|
16
|
+
|
|
17
|
+
This function handles both cases:
|
|
18
|
+
1. When called from within an existing event loop (runs in a thread)
|
|
19
|
+
2. When called from a synchronous context (creates new event loop)
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
async_func: The async function to run
|
|
23
|
+
*args: Positional arguments for the function
|
|
24
|
+
**kwargs: Keyword arguments for the function
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
The result of the async function
|
|
28
|
+
"""
|
|
29
|
+
def run_in_new_loop():
|
|
30
|
+
"""Run the async function in a new event loop."""
|
|
31
|
+
loop = asyncio.new_event_loop()
|
|
32
|
+
asyncio.set_event_loop(loop)
|
|
33
|
+
try:
|
|
34
|
+
result = loop.run_until_complete(async_func(*args, **kwargs))
|
|
35
|
+
# Wait for all tasks to complete
|
|
36
|
+
pending = asyncio.all_tasks(loop)
|
|
37
|
+
if pending:
|
|
38
|
+
loop.run_until_complete(asyncio.gather(*pending, return_exceptions=True))
|
|
39
|
+
return result
|
|
40
|
+
finally:
|
|
41
|
+
# Cancel any remaining tasks
|
|
42
|
+
pending = asyncio.all_tasks(loop)
|
|
43
|
+
for task in pending:
|
|
44
|
+
task.cancel()
|
|
45
|
+
if pending:
|
|
46
|
+
loop.run_until_complete(asyncio.gather(*pending, return_exceptions=True))
|
|
47
|
+
loop.close()
|
|
48
|
+
|
|
49
|
+
try:
|
|
50
|
+
# Check if we're in an async context
|
|
51
|
+
asyncio.get_running_loop()
|
|
52
|
+
# We're in an async context, run in a thread
|
|
53
|
+
with concurrent.futures.ThreadPoolExecutor() as executor:
|
|
54
|
+
future = executor.submit(run_in_new_loop)
|
|
55
|
+
return future.result()
|
|
56
|
+
except RuntimeError:
|
|
57
|
+
# No event loop running, we can run directly
|
|
58
|
+
return run_in_new_loop()
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def async_to_sync(async_func: Callable[..., Awaitable[T]]) -> Callable[..., T]:
|
|
62
|
+
"""
|
|
63
|
+
Decorator to create a synchronous version of an async function.
|
|
64
|
+
|
|
65
|
+
Usage:
|
|
66
|
+
@async_to_sync
|
|
67
|
+
async def my_async_func():
|
|
68
|
+
await asyncio.sleep(1)
|
|
69
|
+
return "done"
|
|
70
|
+
|
|
71
|
+
# Can now be called synchronously
|
|
72
|
+
result = my_async_func()
|
|
73
|
+
"""
|
|
74
|
+
@wraps(async_func)
|
|
75
|
+
def wrapper(*args, **kwargs):
|
|
76
|
+
return run_async_in_sync(async_func, *args, **kwargs)
|
|
77
|
+
return wrapper
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class AsyncSyncMixin:
|
|
81
|
+
"""
|
|
82
|
+
Mixin class that provides automatic sync versions of async methods.
|
|
83
|
+
|
|
84
|
+
For any async method `foo`, this mixin automatically provides a `foo_sync` method.
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
def __getattr__(self, name: str) -> Any:
|
|
88
|
+
if name.endswith('_sync'):
|
|
89
|
+
async_name = name[:-5] # Remove '_sync' suffix
|
|
90
|
+
async_method = getattr(self, async_name, None)
|
|
91
|
+
|
|
92
|
+
if async_method and asyncio.iscoroutinefunction(async_method):
|
|
93
|
+
# Create a sync wrapper
|
|
94
|
+
def sync_wrapper(*args, **kwargs):
|
|
95
|
+
return run_async_in_sync(async_method, *args, **kwargs)
|
|
96
|
+
|
|
97
|
+
# Cache it for future calls
|
|
98
|
+
setattr(self, name, sync_wrapper)
|
|
99
|
+
return sync_wrapper
|
|
100
|
+
|
|
101
|
+
raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")
|