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,632 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Performance tests for Shell Commands module.
|
|
3
|
+
|
|
4
|
+
This module provides performance tests to verify that the shell commands
|
|
5
|
+
system performs well under various load conditions including high
|
|
6
|
+
throughput, concurrent operations, memory usage, and stress scenarios.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import unittest
|
|
10
|
+
import pytest
|
|
11
|
+
import time
|
|
12
|
+
import threading
|
|
13
|
+
import tempfile
|
|
14
|
+
import os
|
|
15
|
+
import psutil
|
|
16
|
+
import statistics
|
|
17
|
+
from typing import List, Dict, Any, Tuple
|
|
18
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
19
|
+
|
|
20
|
+
from autocoder.common.shell_commands import (
|
|
21
|
+
CommandExecutor,
|
|
22
|
+
TimeoutConfig,
|
|
23
|
+
execute_command,
|
|
24
|
+
execute_command_background,
|
|
25
|
+
execute_commands,
|
|
26
|
+
get_background_processes,
|
|
27
|
+
cleanup_background_process,
|
|
28
|
+
InteractiveCommandExecutor,
|
|
29
|
+
get_session_manager,
|
|
30
|
+
get_background_process_notifier
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class PerformanceTestCase(unittest.TestCase):
|
|
35
|
+
"""Base class for performance tests with common utilities."""
|
|
36
|
+
|
|
37
|
+
def setUp(self):
|
|
38
|
+
"""Set up performance test environment."""
|
|
39
|
+
self.temp_dir = tempfile.mkdtemp()
|
|
40
|
+
self.start_memory = self._get_memory_usage()
|
|
41
|
+
self.performance_data = {}
|
|
42
|
+
|
|
43
|
+
def tearDown(self):
|
|
44
|
+
"""Clean up performance test environment."""
|
|
45
|
+
# Clean up any remaining processes
|
|
46
|
+
try:
|
|
47
|
+
bg_processes = get_background_processes()
|
|
48
|
+
for pid in bg_processes.keys():
|
|
49
|
+
cleanup_background_process(pid)
|
|
50
|
+
except:
|
|
51
|
+
pass
|
|
52
|
+
|
|
53
|
+
# Clean up sessions
|
|
54
|
+
try:
|
|
55
|
+
manager = get_session_manager()
|
|
56
|
+
manager.cleanup_all()
|
|
57
|
+
except:
|
|
58
|
+
pass
|
|
59
|
+
|
|
60
|
+
import shutil
|
|
61
|
+
try:
|
|
62
|
+
shutil.rmtree(self.temp_dir)
|
|
63
|
+
except:
|
|
64
|
+
pass
|
|
65
|
+
|
|
66
|
+
# Report memory usage
|
|
67
|
+
end_memory = self._get_memory_usage()
|
|
68
|
+
memory_diff = end_memory - self.start_memory
|
|
69
|
+
if memory_diff > 50 * 1024 * 1024: # 50MB threshold
|
|
70
|
+
print(f"Warning: Memory usage increased by {memory_diff / 1024 / 1024:.1f}MB")
|
|
71
|
+
|
|
72
|
+
def _get_memory_usage(self) -> int:
|
|
73
|
+
"""Get current process memory usage in bytes."""
|
|
74
|
+
try:
|
|
75
|
+
process = psutil.Process()
|
|
76
|
+
return process.memory_info().rss
|
|
77
|
+
except:
|
|
78
|
+
return 0
|
|
79
|
+
|
|
80
|
+
def _measure_time(self, func, *args, **kwargs):
|
|
81
|
+
"""Measure execution time of a function."""
|
|
82
|
+
start_time = time.time()
|
|
83
|
+
result = func(*args, **kwargs)
|
|
84
|
+
end_time = time.time()
|
|
85
|
+
return result, end_time - start_time
|
|
86
|
+
|
|
87
|
+
def _measure_throughput(self, func, iterations: int, *args, **kwargs) -> Tuple[List[Any], float]:
|
|
88
|
+
"""Measure throughput of a function over multiple iterations."""
|
|
89
|
+
results = []
|
|
90
|
+
start_time = time.time()
|
|
91
|
+
|
|
92
|
+
for _ in range(iterations):
|
|
93
|
+
result = func(*args, **kwargs)
|
|
94
|
+
results.append(result)
|
|
95
|
+
|
|
96
|
+
end_time = time.time()
|
|
97
|
+
total_time = end_time - start_time
|
|
98
|
+
throughput = iterations / total_time if total_time > 0 else 0
|
|
99
|
+
|
|
100
|
+
return results, throughput
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@pytest.mark.performance
|
|
104
|
+
class TestCommandExecutionPerformance(PerformanceTestCase):
|
|
105
|
+
"""Test command execution performance."""
|
|
106
|
+
|
|
107
|
+
def test_single_command_performance(self):
|
|
108
|
+
"""Test performance of single command execution."""
|
|
109
|
+
config = TimeoutConfig(default_timeout=30.0)
|
|
110
|
+
executor = CommandExecutor(config=config)
|
|
111
|
+
|
|
112
|
+
try:
|
|
113
|
+
# Measure simple command execution
|
|
114
|
+
_, duration = self._measure_time(
|
|
115
|
+
executor.execute, "echo 'performance test'"
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
# Should complete quickly
|
|
119
|
+
self.assertLess(duration, 1.0, "Simple command should complete in under 1 second")
|
|
120
|
+
|
|
121
|
+
# Measure multiple executions for consistency
|
|
122
|
+
durations = []
|
|
123
|
+
for _ in range(10):
|
|
124
|
+
_, duration = self._measure_time(
|
|
125
|
+
executor.execute, "echo 'test'"
|
|
126
|
+
)
|
|
127
|
+
durations.append(duration)
|
|
128
|
+
|
|
129
|
+
avg_duration = statistics.mean(durations)
|
|
130
|
+
std_deviation = statistics.stdev(durations) if len(durations) > 1 else 0
|
|
131
|
+
|
|
132
|
+
self.assertLess(avg_duration, 0.5, "Average execution time should be reasonable")
|
|
133
|
+
self.assertLess(std_deviation, 0.2, "Execution time should be consistent")
|
|
134
|
+
|
|
135
|
+
finally:
|
|
136
|
+
executor.cleanup()
|
|
137
|
+
|
|
138
|
+
def test_concurrent_command_execution_performance(self):
|
|
139
|
+
"""Test performance under concurrent command execution."""
|
|
140
|
+
num_threads = 10
|
|
141
|
+
commands_per_thread = 5
|
|
142
|
+
|
|
143
|
+
def execute_commands_worker():
|
|
144
|
+
config = TimeoutConfig(default_timeout=10.0)
|
|
145
|
+
executor = CommandExecutor(config=config)
|
|
146
|
+
durations = []
|
|
147
|
+
|
|
148
|
+
try:
|
|
149
|
+
for i in range(commands_per_thread):
|
|
150
|
+
_, duration = self._measure_time(
|
|
151
|
+
executor.execute, f"echo 'worker command {i}'"
|
|
152
|
+
)
|
|
153
|
+
durations.append(duration)
|
|
154
|
+
return durations
|
|
155
|
+
finally:
|
|
156
|
+
executor.cleanup()
|
|
157
|
+
|
|
158
|
+
# Execute commands concurrently
|
|
159
|
+
start_time = time.time()
|
|
160
|
+
with ThreadPoolExecutor(max_workers=num_threads) as executor:
|
|
161
|
+
futures = [executor.submit(execute_commands_worker) for _ in range(num_threads)]
|
|
162
|
+
results = [future.result() for future in as_completed(futures)]
|
|
163
|
+
|
|
164
|
+
total_time = time.time() - start_time
|
|
165
|
+
|
|
166
|
+
# Calculate statistics
|
|
167
|
+
all_durations = [duration for worker_durations in results for duration in worker_durations]
|
|
168
|
+
total_commands = num_threads * commands_per_thread
|
|
169
|
+
avg_duration = statistics.mean(all_durations)
|
|
170
|
+
throughput = total_commands / total_time
|
|
171
|
+
|
|
172
|
+
# Performance assertions
|
|
173
|
+
self.assertGreater(throughput, 10, "Should achieve reasonable throughput")
|
|
174
|
+
self.assertLess(avg_duration, 2.0, "Average command duration should be reasonable")
|
|
175
|
+
self.assertLess(total_time, 30.0, "Total execution time should be reasonable")
|
|
176
|
+
|
|
177
|
+
print(f"Concurrent execution: {total_commands} commands in {total_time:.2f}s "
|
|
178
|
+
f"(throughput: {throughput:.1f} cmd/s, avg: {avg_duration:.3f}s)")
|
|
179
|
+
|
|
180
|
+
def test_batch_execution_performance(self):
|
|
181
|
+
"""Test batch execution performance."""
|
|
182
|
+
# Test parallel batch execution
|
|
183
|
+
commands = [f"echo 'batch command {i}'" for i in range(20)]
|
|
184
|
+
|
|
185
|
+
# Measure parallel execution
|
|
186
|
+
parallel_results, parallel_time = self._measure_time(
|
|
187
|
+
execute_commands, commands, parallel=True, timeout=30.0
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
# Measure serial execution
|
|
191
|
+
serial_results, serial_time = self._measure_time(
|
|
192
|
+
execute_commands, commands, parallel=False, timeout=60.0
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
# Verify all commands succeeded
|
|
196
|
+
self.assertEqual(len(parallel_results), 20)
|
|
197
|
+
self.assertEqual(len(serial_results), 20)
|
|
198
|
+
|
|
199
|
+
for result in parallel_results + serial_results:
|
|
200
|
+
self.assertEqual(result["exit_code"], 0)
|
|
201
|
+
|
|
202
|
+
# Parallel should be significantly faster for I/O bound tasks
|
|
203
|
+
speedup_ratio = serial_time / parallel_time if parallel_time > 0 else 1
|
|
204
|
+
|
|
205
|
+
print(f"Batch execution: Parallel {parallel_time:.2f}s vs Serial {serial_time:.2f}s "
|
|
206
|
+
f"(speedup: {speedup_ratio:.1f}x)")
|
|
207
|
+
|
|
208
|
+
# Allow for some overhead, but parallel should still be faster
|
|
209
|
+
self.assertLess(parallel_time, serial_time * 0.8,
|
|
210
|
+
"Parallel execution should be significantly faster")
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
@pytest.mark.performance
|
|
214
|
+
class TestBackgroundProcessPerformance(PerformanceTestCase):
|
|
215
|
+
"""Test background process performance."""
|
|
216
|
+
|
|
217
|
+
def test_background_process_creation_performance(self):
|
|
218
|
+
"""Test performance of background process creation."""
|
|
219
|
+
num_processes = 20
|
|
220
|
+
processes = []
|
|
221
|
+
|
|
222
|
+
try:
|
|
223
|
+
# Measure batch creation
|
|
224
|
+
creation_durations = []
|
|
225
|
+
for i in range(num_processes):
|
|
226
|
+
_, duration = self._measure_time(
|
|
227
|
+
execute_command_background,
|
|
228
|
+
f"python -c \"import time; print('bg {i}'); time.sleep(0.1)\"",
|
|
229
|
+
cwd=self.temp_dir
|
|
230
|
+
)
|
|
231
|
+
creation_durations.append(duration)
|
|
232
|
+
# Track for cleanup
|
|
233
|
+
processes.append(_)
|
|
234
|
+
|
|
235
|
+
avg_creation_time = statistics.mean(creation_durations)
|
|
236
|
+
max_creation_time = max(creation_durations)
|
|
237
|
+
|
|
238
|
+
# Performance assertions
|
|
239
|
+
self.assertLess(avg_creation_time, 0.5, "Background process creation should be fast")
|
|
240
|
+
self.assertLess(max_creation_time, 2.0, "No single creation should be too slow")
|
|
241
|
+
|
|
242
|
+
print(f"Background process creation: avg {avg_creation_time:.3f}s, "
|
|
243
|
+
f"max {max_creation_time:.3f}s for {num_processes} processes")
|
|
244
|
+
|
|
245
|
+
# Verify all processes are tracked
|
|
246
|
+
bg_processes = get_background_processes()
|
|
247
|
+
active_count = len([p for p in bg_processes.values() if p.get("status") == "running"])
|
|
248
|
+
self.assertGreaterEqual(active_count, num_processes * 0.5) # At least half should still be running
|
|
249
|
+
|
|
250
|
+
finally:
|
|
251
|
+
# Clean up all processes
|
|
252
|
+
for info in processes:
|
|
253
|
+
if isinstance(info, dict) and "pid" in info:
|
|
254
|
+
cleanup_background_process(info["pid"])
|
|
255
|
+
|
|
256
|
+
def test_background_process_monitoring_performance(self):
|
|
257
|
+
"""Test performance of background process monitoring."""
|
|
258
|
+
num_processes = 10
|
|
259
|
+
processes = []
|
|
260
|
+
|
|
261
|
+
try:
|
|
262
|
+
# Start background processes
|
|
263
|
+
for i in range(num_processes):
|
|
264
|
+
info = execute_command_background(
|
|
265
|
+
f"python -c \"import time; time.sleep(2); print('done {i}')\"",
|
|
266
|
+
cwd=self.temp_dir
|
|
267
|
+
)
|
|
268
|
+
processes.append(info)
|
|
269
|
+
|
|
270
|
+
# Measure monitoring performance
|
|
271
|
+
monitoring_durations = []
|
|
272
|
+
for _ in range(20): # Multiple monitoring cycles
|
|
273
|
+
_, duration = self._measure_time(get_background_processes)
|
|
274
|
+
monitoring_durations.append(duration)
|
|
275
|
+
time.sleep(0.1)
|
|
276
|
+
|
|
277
|
+
avg_monitoring_time = statistics.mean(monitoring_durations)
|
|
278
|
+
max_monitoring_time = max(monitoring_durations)
|
|
279
|
+
|
|
280
|
+
# Performance assertions
|
|
281
|
+
self.assertLess(avg_monitoring_time, 0.1, "Process monitoring should be fast")
|
|
282
|
+
self.assertLess(max_monitoring_time, 0.5, "No monitoring call should be too slow")
|
|
283
|
+
|
|
284
|
+
print(f"Background process monitoring: avg {avg_monitoring_time:.3f}s, "
|
|
285
|
+
f"max {max_monitoring_time:.3f}s per call")
|
|
286
|
+
|
|
287
|
+
finally:
|
|
288
|
+
# Clean up
|
|
289
|
+
for info in processes:
|
|
290
|
+
cleanup_background_process(info["pid"])
|
|
291
|
+
|
|
292
|
+
def test_background_process_notifier_performance(self):
|
|
293
|
+
"""Test background process notifier performance."""
|
|
294
|
+
import uuid
|
|
295
|
+
|
|
296
|
+
conv_id = f"perf-test-{uuid.uuid4()}"
|
|
297
|
+
notifier = get_background_process_notifier()
|
|
298
|
+
num_processes = 15
|
|
299
|
+
processes = []
|
|
300
|
+
|
|
301
|
+
try:
|
|
302
|
+
# Start multiple background processes and register them
|
|
303
|
+
registration_durations = []
|
|
304
|
+
for i in range(num_processes):
|
|
305
|
+
info = execute_command_background(
|
|
306
|
+
f"python -c \"import time; time.sleep(0.5); print('notifier test {i}')\"",
|
|
307
|
+
cwd=self.temp_dir
|
|
308
|
+
)
|
|
309
|
+
processes.append(info)
|
|
310
|
+
|
|
311
|
+
# Measure registration time
|
|
312
|
+
_, duration = self._measure_time(
|
|
313
|
+
notifier.register_process,
|
|
314
|
+
conversation_id=conv_id,
|
|
315
|
+
pid=info["pid"],
|
|
316
|
+
tool_name="perf_test",
|
|
317
|
+
command=info["command"],
|
|
318
|
+
cwd=self.temp_dir
|
|
319
|
+
)
|
|
320
|
+
registration_durations.append(duration)
|
|
321
|
+
|
|
322
|
+
avg_registration_time = statistics.mean(registration_durations)
|
|
323
|
+
|
|
324
|
+
# Test message polling performance
|
|
325
|
+
polling_durations = []
|
|
326
|
+
total_messages = 0
|
|
327
|
+
|
|
328
|
+
# Poll for completion messages
|
|
329
|
+
deadline = time.time() + 30.0
|
|
330
|
+
while time.time() < deadline:
|
|
331
|
+
_, duration = self._measure_time(
|
|
332
|
+
notifier.poll_messages, conv_id, 10
|
|
333
|
+
)
|
|
334
|
+
polling_durations.append(duration)
|
|
335
|
+
|
|
336
|
+
messages = notifier.poll_messages(conv_id, 10)
|
|
337
|
+
total_messages += len(messages)
|
|
338
|
+
|
|
339
|
+
if total_messages >= num_processes:
|
|
340
|
+
break
|
|
341
|
+
|
|
342
|
+
time.sleep(0.1)
|
|
343
|
+
|
|
344
|
+
if polling_durations:
|
|
345
|
+
avg_polling_time = statistics.mean(polling_durations)
|
|
346
|
+
max_polling_time = max(polling_durations)
|
|
347
|
+
|
|
348
|
+
# Performance assertions
|
|
349
|
+
self.assertLess(avg_registration_time, 0.1, "Process registration should be fast")
|
|
350
|
+
self.assertLess(avg_polling_time, 0.05, "Message polling should be very fast")
|
|
351
|
+
self.assertLess(max_polling_time, 0.2, "No polling should be too slow")
|
|
352
|
+
|
|
353
|
+
print(f"Notifier performance: registration avg {avg_registration_time:.3f}s, "
|
|
354
|
+
f"polling avg {avg_polling_time:.3f}s")
|
|
355
|
+
|
|
356
|
+
finally:
|
|
357
|
+
# Clean up
|
|
358
|
+
for info in processes:
|
|
359
|
+
cleanup_background_process(info["pid"])
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
@pytest.mark.performance
|
|
363
|
+
class TestInteractiveSessionPerformance(PerformanceTestCase):
|
|
364
|
+
"""Test interactive session performance."""
|
|
365
|
+
|
|
366
|
+
def test_session_creation_performance(self):
|
|
367
|
+
"""Test performance of interactive session creation."""
|
|
368
|
+
manager = get_session_manager()
|
|
369
|
+
num_sessions = 10
|
|
370
|
+
session_ids = []
|
|
371
|
+
|
|
372
|
+
try:
|
|
373
|
+
# Measure session creation
|
|
374
|
+
creation_durations = []
|
|
375
|
+
for i in range(num_sessions):
|
|
376
|
+
_, duration = self._measure_time(
|
|
377
|
+
manager.create_session,
|
|
378
|
+
f"python -c \"print('session {i}'); import time; time.sleep(0.5)\"",
|
|
379
|
+
timeout=30,
|
|
380
|
+
use_pexpect=False
|
|
381
|
+
)
|
|
382
|
+
creation_durations.append(duration)
|
|
383
|
+
|
|
384
|
+
if _.success:
|
|
385
|
+
session_ids.append(_.content["session_id"])
|
|
386
|
+
|
|
387
|
+
avg_creation_time = statistics.mean(creation_durations)
|
|
388
|
+
successful_sessions = len(session_ids)
|
|
389
|
+
|
|
390
|
+
# Performance assertions
|
|
391
|
+
self.assertLess(avg_creation_time, 2.0, "Session creation should be reasonably fast")
|
|
392
|
+
self.assertGreaterEqual(successful_sessions, num_sessions * 0.8, "Most sessions should be created successfully")
|
|
393
|
+
|
|
394
|
+
print(f"Session creation: avg {avg_creation_time:.3f}s for {successful_sessions}/{num_sessions} sessions")
|
|
395
|
+
|
|
396
|
+
finally:
|
|
397
|
+
# Clean up sessions
|
|
398
|
+
for session_id in session_ids:
|
|
399
|
+
try:
|
|
400
|
+
manager.terminate_session(session_id)
|
|
401
|
+
except:
|
|
402
|
+
pass
|
|
403
|
+
|
|
404
|
+
def test_session_communication_performance(self):
|
|
405
|
+
"""Test performance of session communication."""
|
|
406
|
+
manager = get_session_manager()
|
|
407
|
+
|
|
408
|
+
# Create a session
|
|
409
|
+
result = manager.create_session(
|
|
410
|
+
"python -c \"import sys; [print(input()) for _ in range(100)]\"",
|
|
411
|
+
timeout=60,
|
|
412
|
+
use_pexpect=False
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
if not result.success:
|
|
416
|
+
self.skipTest("Could not create session for performance test")
|
|
417
|
+
|
|
418
|
+
session_id = result.content["session_id"]
|
|
419
|
+
|
|
420
|
+
try:
|
|
421
|
+
# Measure input/output performance
|
|
422
|
+
communication_durations = []
|
|
423
|
+
for i in range(20):
|
|
424
|
+
# Measure sending input
|
|
425
|
+
_, send_duration = self._measure_time(
|
|
426
|
+
manager.send_input, session_id, f"Message {i}\n"
|
|
427
|
+
)
|
|
428
|
+
|
|
429
|
+
# Small delay to let command process
|
|
430
|
+
time.sleep(0.05)
|
|
431
|
+
|
|
432
|
+
# Measure reading output
|
|
433
|
+
_, read_duration = self._measure_time(
|
|
434
|
+
manager.read_output, session_id
|
|
435
|
+
)
|
|
436
|
+
|
|
437
|
+
total_duration = send_duration + read_duration
|
|
438
|
+
communication_durations.append(total_duration)
|
|
439
|
+
|
|
440
|
+
avg_communication_time = statistics.mean(communication_durations)
|
|
441
|
+
max_communication_time = max(communication_durations)
|
|
442
|
+
|
|
443
|
+
# Performance assertions
|
|
444
|
+
self.assertLess(avg_communication_time, 0.5, "Session communication should be fast")
|
|
445
|
+
self.assertLess(max_communication_time, 2.0, "No single communication should be too slow")
|
|
446
|
+
|
|
447
|
+
print(f"Session communication: avg {avg_communication_time:.3f}s, "
|
|
448
|
+
f"max {max_communication_time:.3f}s per round-trip")
|
|
449
|
+
|
|
450
|
+
finally:
|
|
451
|
+
manager.terminate_session(session_id)
|
|
452
|
+
|
|
453
|
+
def test_concurrent_session_performance(self):
|
|
454
|
+
"""Test performance with multiple concurrent sessions."""
|
|
455
|
+
manager = get_session_manager()
|
|
456
|
+
num_sessions = 8 # Reasonable number for concurrent testing
|
|
457
|
+
|
|
458
|
+
def session_worker(session_index):
|
|
459
|
+
"""Worker function for concurrent session testing."""
|
|
460
|
+
timings = []
|
|
461
|
+
session_id = None
|
|
462
|
+
|
|
463
|
+
try:
|
|
464
|
+
# Create session
|
|
465
|
+
start_time = time.time()
|
|
466
|
+
result = manager.create_session(
|
|
467
|
+
f"python -c \"import time; print('session {session_index} ready'); "
|
|
468
|
+
f"[print(input()) for _ in range(5)]\"",
|
|
469
|
+
timeout=30,
|
|
470
|
+
use_pexpect=False
|
|
471
|
+
)
|
|
472
|
+
creation_time = time.time() - start_time
|
|
473
|
+
|
|
474
|
+
if not result.success:
|
|
475
|
+
return {"error": f"Failed to create session {session_index}"}
|
|
476
|
+
|
|
477
|
+
session_id = result.content["session_id"]
|
|
478
|
+
timings.append(("creation", creation_time))
|
|
479
|
+
|
|
480
|
+
# Perform some communication
|
|
481
|
+
for i in range(5):
|
|
482
|
+
start_time = time.time()
|
|
483
|
+
manager.send_input(session_id, f"Message {i} from session {session_index}\n")
|
|
484
|
+
time.sleep(0.02) # Small delay
|
|
485
|
+
manager.read_output(session_id)
|
|
486
|
+
comm_time = time.time() - start_time
|
|
487
|
+
timings.append(("communication", comm_time))
|
|
488
|
+
|
|
489
|
+
return {"session_index": session_index, "timings": timings}
|
|
490
|
+
|
|
491
|
+
except Exception as e:
|
|
492
|
+
return {"error": f"Session {session_index} error: {str(e)}"}
|
|
493
|
+
finally:
|
|
494
|
+
if session_id:
|
|
495
|
+
try:
|
|
496
|
+
manager.terminate_session(session_id)
|
|
497
|
+
except:
|
|
498
|
+
pass
|
|
499
|
+
|
|
500
|
+
# Execute concurrent sessions
|
|
501
|
+
start_time = time.time()
|
|
502
|
+
with ThreadPoolExecutor(max_workers=num_sessions) as executor:
|
|
503
|
+
futures = [executor.submit(session_worker, i) for i in range(num_sessions)]
|
|
504
|
+
results = [future.result() for future in as_completed(futures)]
|
|
505
|
+
total_time = time.time() - start_time
|
|
506
|
+
|
|
507
|
+
# Analyze results
|
|
508
|
+
successful_sessions = [r for r in results if "error" not in r]
|
|
509
|
+
failed_sessions = [r for r in results if "error" in r]
|
|
510
|
+
|
|
511
|
+
if failed_sessions:
|
|
512
|
+
print(f"Failed sessions: {len(failed_sessions)}")
|
|
513
|
+
for failure in failed_sessions:
|
|
514
|
+
print(f" {failure['error']}")
|
|
515
|
+
|
|
516
|
+
self.assertGreater(len(successful_sessions), num_sessions * 0.7,
|
|
517
|
+
"Most concurrent sessions should succeed")
|
|
518
|
+
|
|
519
|
+
if successful_sessions:
|
|
520
|
+
all_timings = []
|
|
521
|
+
for session_result in successful_sessions:
|
|
522
|
+
all_timings.extend(session_result["timings"])
|
|
523
|
+
|
|
524
|
+
creation_times = [t[1] for t in all_timings if t[0] == "creation"]
|
|
525
|
+
communication_times = [t[1] for t in all_timings if t[0] == "communication"]
|
|
526
|
+
|
|
527
|
+
if creation_times:
|
|
528
|
+
avg_creation = statistics.mean(creation_times)
|
|
529
|
+
print(f"Concurrent sessions: {len(successful_sessions)} sessions, "
|
|
530
|
+
f"avg creation {avg_creation:.3f}s, total time {total_time:.2f}s")
|
|
531
|
+
|
|
532
|
+
self.assertLess(avg_creation, 5.0, "Concurrent session creation should be reasonable")
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
@pytest.mark.performance
|
|
536
|
+
class TestMemoryPerformance(PerformanceTestCase):
|
|
537
|
+
"""Test memory usage performance."""
|
|
538
|
+
|
|
539
|
+
def test_memory_usage_under_load(self):
|
|
540
|
+
"""Test memory usage under high load."""
|
|
541
|
+
initial_memory = self._get_memory_usage()
|
|
542
|
+
|
|
543
|
+
# Create multiple executors and run commands
|
|
544
|
+
executors = []
|
|
545
|
+
try:
|
|
546
|
+
for i in range(10):
|
|
547
|
+
config = TimeoutConfig(default_timeout=30.0)
|
|
548
|
+
executor = CommandExecutor(config=config)
|
|
549
|
+
executors.append(executor)
|
|
550
|
+
|
|
551
|
+
# Execute some commands
|
|
552
|
+
for j in range(5):
|
|
553
|
+
executor.execute(f"echo 'executor {i} command {j}'")
|
|
554
|
+
|
|
555
|
+
# Check memory usage after load
|
|
556
|
+
peak_memory = self._get_memory_usage()
|
|
557
|
+
memory_increase = peak_memory - initial_memory
|
|
558
|
+
|
|
559
|
+
print(f"Memory usage: initial {initial_memory // 1024 // 1024}MB, "
|
|
560
|
+
f"peak {peak_memory // 1024 // 1024}MB, "
|
|
561
|
+
f"increase {memory_increase // 1024 // 1024}MB")
|
|
562
|
+
|
|
563
|
+
# Memory increase should be reasonable (less than 100MB for this test)
|
|
564
|
+
self.assertLess(memory_increase, 100 * 1024 * 1024,
|
|
565
|
+
"Memory usage should not increase excessively")
|
|
566
|
+
|
|
567
|
+
finally:
|
|
568
|
+
# Clean up executors
|
|
569
|
+
for executor in executors:
|
|
570
|
+
executor.cleanup()
|
|
571
|
+
|
|
572
|
+
# Force garbage collection
|
|
573
|
+
import gc
|
|
574
|
+
gc.collect()
|
|
575
|
+
|
|
576
|
+
# Check memory after cleanup
|
|
577
|
+
final_memory = self._get_memory_usage()
|
|
578
|
+
memory_after_cleanup = final_memory - initial_memory
|
|
579
|
+
|
|
580
|
+
print(f"Memory after cleanup: {final_memory // 1024 // 1024}MB, "
|
|
581
|
+
f"net increase {memory_after_cleanup // 1024 // 1024}MB")
|
|
582
|
+
|
|
583
|
+
def test_background_process_memory_scaling(self):
|
|
584
|
+
"""Test memory usage with many background processes."""
|
|
585
|
+
initial_memory = self._get_memory_usage()
|
|
586
|
+
processes = []
|
|
587
|
+
|
|
588
|
+
try:
|
|
589
|
+
# Start many short-lived background processes
|
|
590
|
+
for i in range(50):
|
|
591
|
+
info = execute_command_background(
|
|
592
|
+
f"python -c \"import time; time.sleep(0.2); print('done {i}')\"",
|
|
593
|
+
cwd=self.temp_dir
|
|
594
|
+
)
|
|
595
|
+
processes.append(info)
|
|
596
|
+
|
|
597
|
+
# Check memory periodically
|
|
598
|
+
if i % 10 == 0:
|
|
599
|
+
current_memory = self._get_memory_usage()
|
|
600
|
+
memory_per_process = (current_memory - initial_memory) // (i + 1) if i > 0 else 0
|
|
601
|
+
print(f"After {i+1} processes: {memory_per_process // 1024}KB per process")
|
|
602
|
+
|
|
603
|
+
# Wait for processes to complete
|
|
604
|
+
deadline = time.time() + 30.0
|
|
605
|
+
while time.time() < deadline:
|
|
606
|
+
bg_processes = get_background_processes()
|
|
607
|
+
active_count = len([p for p in bg_processes.values() if p.get("status") == "running"])
|
|
608
|
+
if active_count == 0:
|
|
609
|
+
break
|
|
610
|
+
time.sleep(0.5)
|
|
611
|
+
|
|
612
|
+
peak_memory = self._get_memory_usage()
|
|
613
|
+
total_increase = peak_memory - initial_memory
|
|
614
|
+
memory_per_process = total_increase // len(processes)
|
|
615
|
+
|
|
616
|
+
print(f"Memory scaling: {len(processes)} processes, "
|
|
617
|
+
f"total increase {total_increase // 1024 // 1024}MB, "
|
|
618
|
+
f"~{memory_per_process // 1024}KB per process")
|
|
619
|
+
|
|
620
|
+
# Each process shouldn't use excessive memory
|
|
621
|
+
self.assertLess(memory_per_process, 5 * 1024 * 1024, # 5MB per process
|
|
622
|
+
"Memory per process should be reasonable")
|
|
623
|
+
|
|
624
|
+
finally:
|
|
625
|
+
# Clean up
|
|
626
|
+
for info in processes:
|
|
627
|
+
cleanup_background_process(info["pid"])
|
|
628
|
+
|
|
629
|
+
|
|
630
|
+
if __name__ == "__main__":
|
|
631
|
+
# Run performance tests with verbose output
|
|
632
|
+
unittest.main(verbosity=2)
|