auto-coder 1.0.0__py3-none-any.whl → 2.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of auto-coder might be problematic. Click here for more details.
- auto_coder-2.0.1.dist-info/LICENSE +158 -0
- auto_coder-2.0.1.dist-info/METADATA +558 -0
- auto_coder-2.0.1.dist-info/RECORD +795 -0
- {auto_coder-1.0.0.dist-info → auto_coder-2.0.1.dist-info}/WHEEL +1 -1
- {auto_coder-1.0.0.dist-info → auto_coder-2.0.1.dist-info}/entry_points.txt +3 -3
- autocoder/__init__.py +31 -0
- autocoder/agent/auto_filegroup.py +32 -13
- autocoder/agent/auto_learn_from_commit.py +9 -1
- autocoder/agent/base_agentic/__init__.py +3 -0
- autocoder/agent/base_agentic/agent_hub.py +1 -1
- autocoder/agent/base_agentic/base_agent.py +235 -136
- autocoder/agent/base_agentic/default_tools.py +119 -118
- autocoder/agent/base_agentic/test_base_agent.py +1 -1
- autocoder/agent/base_agentic/tool_registry.py +32 -20
- autocoder/agent/base_agentic/tools/read_file_tool_resolver.py +24 -3
- autocoder/agent/base_agentic/tools/write_to_file_tool_resolver.py +24 -11
- autocoder/agent/base_agentic/types.py +42 -0
- autocoder/agent/entry_command_agent/chat.py +77 -73
- autocoder/auto_coder.py +31 -40
- autocoder/auto_coder_rag.py +11 -1084
- autocoder/auto_coder_runner.py +962 -2345
- autocoder/auto_coder_terminal.py +26 -0
- autocoder/auto_coder_terminal_v3.py +190 -0
- autocoder/chat/conf_command.py +224 -124
- autocoder/chat/models_command.py +361 -299
- autocoder/chat/rules_command.py +79 -31
- autocoder/chat_auto_coder.py +988 -398
- autocoder/chat_auto_coder_lang.py +23 -732
- autocoder/commands/auto_command.py +25 -8
- autocoder/commands/auto_web.py +1 -1
- autocoder/commands/tools.py +44 -44
- autocoder/common/__init__.py +150 -128
- autocoder/common/ac_style_command_parser/__init__.py +39 -2
- autocoder/common/ac_style_command_parser/config.py +422 -0
- autocoder/common/ac_style_command_parser/parser.py +292 -78
- autocoder/common/ac_style_command_parser/test_parser.py +241 -16
- autocoder/common/ac_style_command_parser/test_typed_parser.py +342 -0
- autocoder/common/ac_style_command_parser/typed_parser.py +653 -0
- autocoder/common/action_yml_file_manager.py +25 -13
- autocoder/common/agent_events/__init__.py +52 -0
- autocoder/common/agent_events/agent_event_emitter.py +193 -0
- autocoder/common/agent_events/event_factory.py +177 -0
- autocoder/common/agent_events/examples.py +307 -0
- autocoder/common/agent_events/types.py +113 -0
- autocoder/common/agent_events/utils.py +68 -0
- autocoder/common/agent_hooks/__init__.py +44 -0
- autocoder/common/agent_hooks/examples.py +582 -0
- autocoder/common/agent_hooks/hook_executor.py +217 -0
- autocoder/common/agent_hooks/hook_manager.py +288 -0
- autocoder/common/agent_hooks/types.py +133 -0
- autocoder/common/agent_hooks/utils.py +99 -0
- autocoder/common/agent_query_queue/queue_executor.py +324 -0
- autocoder/common/agent_query_queue/queue_manager.py +325 -0
- autocoder/common/agents/__init__.py +11 -0
- autocoder/common/agents/agent_manager.py +323 -0
- autocoder/common/agents/agent_parser.py +189 -0
- autocoder/common/agents/example_usage.py +344 -0
- autocoder/common/agents/integration_example.py +330 -0
- autocoder/common/agents/test_agent_parser.py +545 -0
- autocoder/common/async_utils.py +101 -0
- autocoder/common/auto_coder_lang.py +23 -972
- autocoder/common/autocoderargs_parser/__init__.py +14 -0
- autocoder/common/autocoderargs_parser/parser.py +184 -0
- autocoder/common/autocoderargs_parser/tests/__init__.py +1 -0
- autocoder/common/autocoderargs_parser/tests/test_args_parser.py +235 -0
- autocoder/common/autocoderargs_parser/tests/test_token_parser.py +195 -0
- autocoder/common/autocoderargs_parser/token_parser.py +290 -0
- autocoder/common/buildin_tokenizer.py +2 -4
- autocoder/common/code_auto_generate.py +149 -74
- autocoder/common/code_auto_generate_diff.py +163 -70
- autocoder/common/code_auto_generate_editblock.py +179 -89
- autocoder/common/code_auto_generate_strict_diff.py +167 -72
- autocoder/common/code_auto_merge_editblock.py +13 -6
- autocoder/common/code_modification_ranker.py +1 -1
- autocoder/common/command_completer.py +3 -3
- autocoder/common/command_file_manager/manager.py +183 -47
- autocoder/common/command_file_manager/test_command_file_manager.py +507 -0
- autocoder/common/command_templates.py +1 -1
- autocoder/common/conf_utils.py +2 -4
- autocoder/common/conversations/config.py +11 -3
- autocoder/common/conversations/get_conversation_manager.py +100 -2
- autocoder/common/conversations/llm_stats_models.py +264 -0
- autocoder/common/conversations/manager.py +112 -28
- autocoder/common/conversations/models.py +16 -2
- autocoder/common/conversations/storage/index_manager.py +134 -10
- autocoder/common/core_config/__init__.py +63 -0
- autocoder/common/core_config/agentic_mode_manager.py +109 -0
- autocoder/common/core_config/base_manager.py +123 -0
- autocoder/common/core_config/compatibility.py +151 -0
- autocoder/common/core_config/config_manager.py +156 -0
- autocoder/common/core_config/conversation_manager.py +31 -0
- autocoder/common/core_config/exclude_manager.py +72 -0
- autocoder/common/core_config/file_manager.py +177 -0
- autocoder/common/core_config/human_as_model_manager.py +129 -0
- autocoder/common/core_config/lib_manager.py +54 -0
- autocoder/common/core_config/main_manager.py +81 -0
- autocoder/common/core_config/mode_manager.py +126 -0
- autocoder/common/core_config/models.py +70 -0
- autocoder/common/core_config/test_memory_manager.py +1056 -0
- autocoder/common/env_manager.py +282 -0
- autocoder/common/env_manager_usage_example.py +211 -0
- autocoder/common/file_checkpoint/conversation_checkpoint.py +19 -19
- autocoder/common/file_checkpoint/manager.py +264 -48
- autocoder/common/file_checkpoint/test_backup.py +1 -18
- autocoder/common/file_checkpoint/test_manager.py +270 -1
- autocoder/common/file_checkpoint/test_store.py +1 -17
- autocoder/common/file_handler/__init__.py +23 -0
- autocoder/common/file_handler/active_context_handler.py +159 -0
- autocoder/common/file_handler/add_files_handler.py +409 -0
- autocoder/common/file_handler/chat_handler.py +180 -0
- autocoder/common/file_handler/coding_handler.py +409 -0
- autocoder/common/file_handler/commit_handler.py +200 -0
- autocoder/common/file_handler/lib_handler.py +156 -0
- autocoder/common/file_handler/list_files_handler.py +111 -0
- autocoder/common/file_handler/mcp_handler.py +268 -0
- autocoder/common/file_handler/models_handler.py +493 -0
- autocoder/common/file_handler/remove_files_handler.py +172 -0
- autocoder/common/git_utils.py +44 -8
- autocoder/common/global_cancel.py +15 -6
- autocoder/common/ignorefiles/test_ignore_file_utils.py +1 -1
- autocoder/common/international/__init__.py +31 -0
- autocoder/common/international/demo_international.py +92 -0
- autocoder/common/international/message_manager.py +157 -0
- autocoder/common/international/messages/__init__.py +56 -0
- autocoder/common/international/messages/async_command_messages.py +507 -0
- autocoder/common/international/messages/auto_coder_messages.py +2208 -0
- autocoder/common/international/messages/chat_auto_coder_messages.py +1547 -0
- autocoder/common/international/messages/command_help_messages.py +986 -0
- autocoder/common/international/messages/conversation_command_messages.py +191 -0
- autocoder/common/international/messages/git_helper_plugin_messages.py +159 -0
- autocoder/common/international/messages/queue_command_messages.py +751 -0
- autocoder/common/international/messages/rules_command_messages.py +77 -0
- autocoder/common/international/messages/sdk_messages.py +1707 -0
- autocoder/common/international/messages/token_helper_plugin_messages.py +361 -0
- autocoder/common/international/messages/tool_display_messages.py +1212 -0
- autocoder/common/international/messages/workflow_exception_messages.py +473 -0
- autocoder/common/international/test_international.py +612 -0
- autocoder/common/linter_core/__init__.py +28 -0
- autocoder/common/linter_core/base_linter.py +61 -0
- autocoder/common/linter_core/config_loader.py +271 -0
- autocoder/common/linter_core/formatters/__init__.py +0 -0
- autocoder/common/linter_core/formatters/base_formatter.py +38 -0
- autocoder/common/linter_core/formatters/raw_formatter.py +17 -0
- autocoder/common/linter_core/linter.py +166 -0
- autocoder/common/linter_core/linter_factory.py +216 -0
- autocoder/common/linter_core/linter_manager.py +333 -0
- autocoder/common/linter_core/linters/__init__.py +9 -0
- autocoder/common/linter_core/linters/java_linter.py +342 -0
- autocoder/common/linter_core/linters/python_linter.py +115 -0
- autocoder/common/linter_core/linters/typescript_linter.py +119 -0
- autocoder/common/linter_core/models/__init__.py +7 -0
- autocoder/common/linter_core/models/lint_result.py +91 -0
- autocoder/common/linter_core/models.py +33 -0
- autocoder/common/linter_core/tests/__init__.py +3 -0
- autocoder/common/linter_core/tests/test_config_loader.py +323 -0
- autocoder/common/linter_core/tests/test_config_loading.py +308 -0
- autocoder/common/linter_core/tests/test_factory_manager.py +234 -0
- autocoder/common/linter_core/tests/test_formatters.py +147 -0
- autocoder/common/linter_core/tests/test_integration.py +317 -0
- autocoder/common/linter_core/tests/test_java_linter.py +496 -0
- autocoder/common/linter_core/tests/test_linters.py +265 -0
- autocoder/common/linter_core/tests/test_models.py +81 -0
- autocoder/common/linter_core/tests/verify_config_loading.py +296 -0
- autocoder/common/linter_core/tests/verify_fixes.py +183 -0
- autocoder/common/llm_friendly_package/__init__.py +31 -0
- autocoder/common/llm_friendly_package/base_manager.py +102 -0
- autocoder/common/llm_friendly_package/docs_manager.py +121 -0
- autocoder/common/llm_friendly_package/library_manager.py +171 -0
- autocoder/common/{llm_friendly_package.py → llm_friendly_package/main_manager.py} +204 -231
- autocoder/common/llm_friendly_package/models.py +40 -0
- autocoder/common/llm_friendly_package/test_llm_friendly_package.py +536 -0
- autocoder/common/llms/__init__.py +15 -0
- autocoder/common/llms/demo_error_handling.py +85 -0
- autocoder/common/llms/factory.py +142 -0
- autocoder/common/llms/manager.py +264 -0
- autocoder/common/llms/pricing.py +121 -0
- autocoder/common/llms/registry.py +316 -0
- autocoder/common/llms/schema.py +77 -0
- autocoder/common/llms/simple_demo.py +45 -0
- autocoder/common/llms/test_quick_model.py +116 -0
- autocoder/common/llms/test_remove_functionality.py +182 -0
- autocoder/common/llms/tests/__init__.py +1 -0
- autocoder/common/llms/tests/test_manager.py +330 -0
- autocoder/common/llms/tests/test_registry.py +364 -0
- autocoder/common/mcp_tools/__init__.py +62 -0
- autocoder/common/{mcp_tools.py → mcp_tools/executor.py} +49 -40
- autocoder/common/{mcp_hub.py → mcp_tools/hub.py} +42 -68
- autocoder/common/{mcp_server_install.py → mcp_tools/installer.py} +16 -28
- autocoder/common/{mcp_server.py → mcp_tools/server.py} +176 -48
- autocoder/common/mcp_tools/test_keyboard_interrupt.py +93 -0
- autocoder/common/mcp_tools/test_mcp_tools.py +391 -0
- autocoder/common/{mcp_server_types.py → mcp_tools/types.py} +121 -48
- autocoder/common/mcp_tools/verify_functionality.py +202 -0
- autocoder/common/model_speed_tester.py +32 -26
- autocoder/common/priority_directory_finder/__init__.py +142 -0
- autocoder/common/priority_directory_finder/examples.py +230 -0
- autocoder/common/priority_directory_finder/finder.py +283 -0
- autocoder/common/priority_directory_finder/models.py +236 -0
- autocoder/common/priority_directory_finder/test_priority_directory_finder.py +431 -0
- autocoder/common/project_scanner/__init__.py +18 -0
- autocoder/common/project_scanner/compat.py +77 -0
- autocoder/common/project_scanner/scanner.py +436 -0
- autocoder/common/project_tracker/__init__.py +27 -0
- autocoder/common/project_tracker/api.py +228 -0
- autocoder/common/project_tracker/demo.py +272 -0
- autocoder/common/project_tracker/tracker.py +487 -0
- autocoder/common/project_tracker/types.py +53 -0
- autocoder/common/pruner/__init__.py +67 -0
- autocoder/common/pruner/agentic_conversation_pruner.py +651 -102
- autocoder/common/pruner/conversation_message_ids_api.py +386 -0
- autocoder/common/pruner/conversation_message_ids_manager.py +347 -0
- autocoder/common/pruner/conversation_message_ids_pruner.py +473 -0
- autocoder/common/pruner/conversation_normalizer.py +347 -0
- autocoder/common/pruner/conversation_pruner.py +26 -6
- autocoder/common/pruner/test_agentic_conversation_pruner.py +554 -112
- autocoder/common/pruner/test_conversation_normalizer.py +502 -0
- autocoder/common/pruner/test_tool_content_detector.py +324 -0
- autocoder/common/pruner/tool_content_detector.py +227 -0
- autocoder/common/pruner/tools/__init__.py +18 -0
- autocoder/common/pruner/tools/query_message_ids.py +264 -0
- autocoder/common/pruner/tools/test_agentic_pruning_logic.py +432 -0
- autocoder/common/pruner/tools/test_message_ids_pruning_only.py +192 -0
- autocoder/common/pull_requests/__init__.py +9 -1
- autocoder/common/pull_requests/utils.py +122 -1
- autocoder/common/rag_manager/rag_manager.py +36 -40
- autocoder/common/rulefiles/__init__.py +53 -1
- autocoder/common/rulefiles/api.py +250 -0
- autocoder/common/rulefiles/core/__init__.py +14 -0
- autocoder/common/rulefiles/core/manager.py +241 -0
- autocoder/common/rulefiles/core/selector.py +805 -0
- autocoder/common/rulefiles/models/__init__.py +20 -0
- autocoder/common/rulefiles/models/index.py +16 -0
- autocoder/common/rulefiles/models/init_rule.py +18 -0
- autocoder/common/rulefiles/models/rule_file.py +18 -0
- autocoder/common/rulefiles/models/rule_relevance.py +14 -0
- autocoder/common/rulefiles/models/summary.py +16 -0
- autocoder/common/rulefiles/test_rulefiles.py +776 -0
- autocoder/common/rulefiles/utils/__init__.py +34 -0
- autocoder/common/rulefiles/utils/monitor.py +86 -0
- autocoder/common/rulefiles/utils/parser.py +230 -0
- autocoder/common/save_formatted_log.py +67 -10
- autocoder/common/search_replace.py +8 -1
- autocoder/common/search_replace_patch/__init__.py +24 -0
- autocoder/common/search_replace_patch/base.py +115 -0
- autocoder/common/search_replace_patch/manager.py +248 -0
- autocoder/common/search_replace_patch/patch_replacer.py +304 -0
- autocoder/common/search_replace_patch/similarity_replacer.py +306 -0
- autocoder/common/search_replace_patch/string_replacer.py +181 -0
- autocoder/common/search_replace_patch/tests/__init__.py +3 -0
- autocoder/common/search_replace_patch/tests/run_tests.py +126 -0
- autocoder/common/search_replace_patch/tests/test_base.py +188 -0
- autocoder/common/search_replace_patch/tests/test_empty_line_insert.py +233 -0
- autocoder/common/search_replace_patch/tests/test_integration.py +389 -0
- autocoder/common/search_replace_patch/tests/test_manager.py +351 -0
- autocoder/common/search_replace_patch/tests/test_patch_replacer.py +316 -0
- autocoder/common/search_replace_patch/tests/test_regex_replacer.py +306 -0
- autocoder/common/search_replace_patch/tests/test_similarity_replacer.py +384 -0
- autocoder/common/shell_commands/__init__.py +197 -0
- autocoder/common/shell_commands/background_process_notifier.py +346 -0
- autocoder/common/shell_commands/command_executor.py +1127 -0
- autocoder/common/shell_commands/error_recovery.py +541 -0
- autocoder/common/shell_commands/exceptions.py +120 -0
- autocoder/common/shell_commands/interactive_executor.py +476 -0
- autocoder/common/shell_commands/interactive_pexpect_process.py +623 -0
- autocoder/common/shell_commands/interactive_process.py +744 -0
- autocoder/common/shell_commands/interactive_session_manager.py +1014 -0
- autocoder/common/shell_commands/monitoring.py +529 -0
- autocoder/common/shell_commands/process_cleanup.py +386 -0
- autocoder/common/shell_commands/process_manager.py +606 -0
- autocoder/common/shell_commands/test_interactive_pexpect_process.py +281 -0
- autocoder/common/shell_commands/tests/__init__.py +6 -0
- autocoder/common/shell_commands/tests/conftest.py +118 -0
- autocoder/common/shell_commands/tests/test_background_process_notifier.py +703 -0
- autocoder/common/shell_commands/tests/test_command_executor.py +448 -0
- autocoder/common/shell_commands/tests/test_error_recovery.py +305 -0
- autocoder/common/shell_commands/tests/test_exceptions.py +299 -0
- autocoder/common/shell_commands/tests/test_execute_batch.py +588 -0
- autocoder/common/shell_commands/tests/test_indented_batch_commands.py +244 -0
- autocoder/common/shell_commands/tests/test_integration.py +664 -0
- autocoder/common/shell_commands/tests/test_monitoring.py +546 -0
- autocoder/common/shell_commands/tests/test_performance.py +632 -0
- autocoder/common/shell_commands/tests/test_process_cleanup.py +397 -0
- autocoder/common/shell_commands/tests/test_process_manager.py +606 -0
- autocoder/common/shell_commands/tests/test_timeout_config.py +343 -0
- autocoder/common/shell_commands/tests/test_timeout_manager.py +520 -0
- autocoder/common/shell_commands/timeout_config.py +315 -0
- autocoder/common/shell_commands/timeout_manager.py +352 -0
- autocoder/common/terminal_paste/__init__.py +14 -0
- autocoder/common/terminal_paste/demo.py +145 -0
- autocoder/common/terminal_paste/demo_paste_functionality.py +95 -0
- autocoder/common/terminal_paste/paste_handler.py +200 -0
- autocoder/common/terminal_paste/paste_manager.py +118 -0
- autocoder/common/terminal_paste/tests/__init__.py +1 -0
- autocoder/common/terminal_paste/tests/test_paste_handler.py +182 -0
- autocoder/common/terminal_paste/tests/test_paste_manager.py +126 -0
- autocoder/common/terminal_paste/utils.py +163 -0
- autocoder/common/test_autocoder_args.py +232 -0
- autocoder/common/test_env_manager.py +173 -0
- autocoder/common/test_env_manager_integration.py +159 -0
- autocoder/common/text_similarity/__init__.py +9 -0
- autocoder/common/text_similarity/demo.py +216 -0
- autocoder/common/text_similarity/examples.py +266 -0
- autocoder/common/text_similarity/test_text_similarity.py +306 -0
- autocoder/common/text_similarity/text_similarity.py +194 -0
- autocoder/common/text_similarity/utils.py +125 -0
- autocoder/common/todos/__init__.py +61 -0
- autocoder/common/todos/cache/__init__.py +16 -0
- autocoder/common/todos/cache/base_cache.py +89 -0
- autocoder/common/todos/cache/cache_manager.py +228 -0
- autocoder/common/todos/cache/memory_cache.py +225 -0
- autocoder/common/todos/config.py +155 -0
- autocoder/common/todos/exceptions.py +35 -0
- autocoder/common/todos/get_todo_manager.py +161 -0
- autocoder/common/todos/manager.py +537 -0
- autocoder/common/todos/models.py +239 -0
- autocoder/common/todos/storage/__init__.py +14 -0
- autocoder/common/todos/storage/base_storage.py +76 -0
- autocoder/common/todos/storage/file_storage.py +278 -0
- autocoder/common/tokens/counter.py +24 -2
- autocoder/common/tools_manager/__init__.py +17 -0
- autocoder/common/tools_manager/examples.py +162 -0
- autocoder/common/tools_manager/manager.py +385 -0
- autocoder/common/tools_manager/models.py +39 -0
- autocoder/common/tools_manager/test_tools_manager.py +303 -0
- autocoder/common/tools_manager/utils.py +191 -0
- autocoder/common/v2/agent/agentic_callbacks.py +270 -0
- autocoder/common/v2/agent/agentic_edit.py +2699 -1856
- autocoder/common/v2/agent/agentic_edit_change_manager.py +474 -0
- autocoder/common/v2/agent/agentic_edit_tools/__init__.py +35 -1
- autocoder/common/v2/agent/agentic_edit_tools/ac_mod_list_tool_resolver.py +279 -0
- autocoder/common/v2/agent/agentic_edit_tools/ac_mod_write_tool_resolver.py +10 -1
- autocoder/common/v2/agent/agentic_edit_tools/background_task_tool_resolver.py +1167 -0
- autocoder/common/v2/agent/agentic_edit_tools/base_tool_resolver.py +2 -2
- autocoder/common/v2/agent/agentic_edit_tools/conversation_message_ids_read_tool_resolver.py +214 -0
- autocoder/common/v2/agent/agentic_edit_tools/conversation_message_ids_write_tool_resolver.py +299 -0
- autocoder/common/v2/agent/agentic_edit_tools/count_tokens_tool_resolver.py +290 -0
- autocoder/common/v2/agent/agentic_edit_tools/execute_command_tool_resolver.py +564 -29
- autocoder/common/v2/agent/agentic_edit_tools/execute_workflow_tool_resolver.py +485 -0
- autocoder/common/v2/agent/agentic_edit_tools/extract_to_text_tool_resolver.py +225 -0
- autocoder/common/v2/agent/agentic_edit_tools/lint_report.py +79 -0
- autocoder/common/v2/agent/agentic_edit_tools/linter_config_models.py +343 -0
- autocoder/common/v2/agent/agentic_edit_tools/linter_enabled_tool_resolver.py +189 -0
- autocoder/common/v2/agent/agentic_edit_tools/list_files_tool_resolver.py +169 -101
- autocoder/common/v2/agent/agentic_edit_tools/load_extra_document_tool_resolver.py +356 -0
- autocoder/common/v2/agent/agentic_edit_tools/read_file_tool_resolver.py +243 -50
- autocoder/common/v2/agent/agentic_edit_tools/replace_in_file_tool_resolver.py +667 -147
- autocoder/common/v2/agent/agentic_edit_tools/run_named_subagents_tool_resolver.py +691 -0
- autocoder/common/v2/agent/agentic_edit_tools/search_files_tool_resolver.py +410 -86
- autocoder/common/v2/agent/agentic_edit_tools/session_interactive_tool_resolver.py +115 -0
- autocoder/common/v2/agent/agentic_edit_tools/session_start_tool_resolver.py +190 -0
- autocoder/common/v2/agent/agentic_edit_tools/session_stop_tool_resolver.py +76 -0
- autocoder/common/v2/agent/agentic_edit_tools/test_write_to_file_tool_resolver.py +207 -192
- autocoder/common/v2/agent/agentic_edit_tools/todo_read_tool_resolver.py +80 -63
- autocoder/common/v2/agent/agentic_edit_tools/todo_write_tool_resolver.py +237 -233
- autocoder/common/v2/agent/agentic_edit_tools/use_mcp_tool_resolver.py +2 -2
- autocoder/common/v2/agent/agentic_edit_tools/web_crawl_tool_resolver.py +557 -0
- autocoder/common/v2/agent/agentic_edit_tools/web_search_tool_resolver.py +600 -0
- autocoder/common/v2/agent/agentic_edit_tools/write_to_file_tool_resolver.py +56 -121
- autocoder/common/v2/agent/agentic_edit_types.py +343 -9
- autocoder/common/v2/agent/runner/__init__.py +3 -3
- autocoder/common/v2/agent/runner/base_runner.py +12 -26
- autocoder/common/v2/agent/runner/{event_runner.py → file_based_event_runner.py} +3 -2
- autocoder/common/v2/agent/runner/sdk_runner.py +150 -8
- autocoder/common/v2/agent/runner/terminal_runner.py +170 -57
- autocoder/common/v2/agent/runner/tool_display.py +557 -159
- autocoder/common/v2/agent/test_agentic_callbacks.py +265 -0
- autocoder/common/v2/agent/test_agentic_edit.py +194 -0
- autocoder/common/v2/agent/tool_caller/__init__.py +24 -0
- autocoder/common/v2/agent/tool_caller/default_tool_resolver_map.py +135 -0
- autocoder/common/v2/agent/tool_caller/integration_test.py +172 -0
- autocoder/common/v2/agent/tool_caller/plugins/__init__.py +14 -0
- autocoder/common/v2/agent/tool_caller/plugins/base_plugin.py +126 -0
- autocoder/common/v2/agent/tool_caller/plugins/examples/__init__.py +13 -0
- autocoder/common/v2/agent/tool_caller/plugins/examples/logging_plugin.py +164 -0
- autocoder/common/v2/agent/tool_caller/plugins/examples/security_filter_plugin.py +198 -0
- autocoder/common/v2/agent/tool_caller/plugins/plugin_interface.py +141 -0
- autocoder/common/v2/agent/tool_caller/test_tool_caller.py +278 -0
- autocoder/common/v2/agent/tool_caller/tool_call_plugin_manager.py +331 -0
- autocoder/common/v2/agent/tool_caller/tool_caller.py +337 -0
- autocoder/common/v2/agent/tool_caller/usage_example.py +193 -0
- autocoder/common/v2/code_agentic_editblock_manager.py +4 -4
- autocoder/common/v2/code_auto_generate.py +136 -78
- autocoder/common/v2/code_auto_generate_diff.py +135 -79
- autocoder/common/v2/code_auto_generate_editblock.py +174 -99
- autocoder/common/v2/code_auto_generate_strict_diff.py +151 -71
- autocoder/common/v2/code_auto_merge.py +1 -1
- autocoder/common/v2/code_auto_merge_editblock.py +13 -1
- autocoder/common/v2/code_diff_manager.py +3 -3
- autocoder/common/v2/code_editblock_manager.py +4 -14
- autocoder/common/v2/code_manager.py +1 -1
- autocoder/common/v2/code_strict_diff_manager.py +2 -2
- autocoder/common/wrap_llm_hint/__init__.py +10 -0
- autocoder/common/wrap_llm_hint/test_wrap_llm_hint.py +1067 -0
- autocoder/common/wrap_llm_hint/utils.py +432 -0
- autocoder/common/wrap_llm_hint/wrap_llm_hint.py +323 -0
- autocoder/completer/__init__.py +8 -0
- autocoder/completer/command_completer_v2.py +1094 -0
- autocoder/default_project/__init__.py +501 -0
- autocoder/dispacher/__init__.py +4 -12
- autocoder/dispacher/actions/action.py +400 -129
- autocoder/dispacher/actions/plugins/action_regex_project.py +2 -2
- autocoder/index/entry.py +117 -125
- autocoder/{agent → index/filter}/agentic_filter.py +322 -333
- autocoder/index/filter/normal_filter.py +5 -11
- autocoder/index/filter/quick_filter.py +1 -1
- autocoder/index/index.py +36 -9
- autocoder/index/tests/__init__.py +1 -0
- autocoder/index/tests/run_tests.py +195 -0
- autocoder/index/tests/test_entry.py +303 -0
- autocoder/index/tests/test_index_manager.py +314 -0
- autocoder/index/tests/test_module_integration.py +300 -0
- autocoder/index/tests/test_symbols_utils.py +183 -0
- autocoder/inner/__init__.py +4 -0
- autocoder/inner/agentic.py +923 -0
- autocoder/inner/async_command_handler.py +992 -0
- autocoder/inner/conversation_command_handlers.py +623 -0
- autocoder/inner/merge_command_handler.py +213 -0
- autocoder/inner/queue_command_handler.py +684 -0
- autocoder/models.py +95 -266
- autocoder/plugins/git_helper_plugin.py +31 -29
- autocoder/plugins/token_helper_plugin.py +65 -46
- autocoder/pyproject/__init__.py +32 -29
- autocoder/rag/agentic_rag.py +215 -75
- autocoder/rag/cache/simple_cache.py +1 -2
- autocoder/rag/loaders/image_loader.py +1 -1
- autocoder/rag/long_context_rag.py +42 -26
- autocoder/rag/qa_conversation_strategy.py +1 -1
- autocoder/rag/terminal/__init__.py +17 -0
- autocoder/rag/terminal/args.py +581 -0
- autocoder/rag/terminal/bootstrap.py +61 -0
- autocoder/rag/terminal/command_handlers.py +653 -0
- autocoder/rag/terminal/formatters/__init__.py +20 -0
- autocoder/rag/terminal/formatters/base.py +70 -0
- autocoder/rag/terminal/formatters/json_format.py +66 -0
- autocoder/rag/terminal/formatters/stream_json.py +95 -0
- autocoder/rag/terminal/formatters/text.py +28 -0
- autocoder/rag/terminal/init.py +120 -0
- autocoder/rag/terminal/utils.py +106 -0
- autocoder/rag/test_agentic_rag.py +389 -0
- autocoder/rag/test_doc_filter.py +3 -3
- autocoder/rag/test_long_context_rag.py +1 -1
- autocoder/rag/test_token_limiter.py +517 -10
- autocoder/rag/token_counter.py +3 -0
- autocoder/rag/token_limiter.py +19 -15
- autocoder/rag/tools/__init__.py +26 -2
- autocoder/rag/tools/bochaai_example.py +343 -0
- autocoder/rag/tools/bochaai_sdk.py +541 -0
- autocoder/rag/tools/metaso_example.py +268 -0
- autocoder/rag/tools/metaso_sdk.py +417 -0
- autocoder/rag/tools/recall_tool.py +28 -7
- autocoder/rag/tools/run_integration_tests.py +204 -0
- autocoder/rag/tools/test_all_providers.py +318 -0
- autocoder/rag/tools/test_bochaai_integration.py +482 -0
- autocoder/rag/tools/test_final_integration.py +215 -0
- autocoder/rag/tools/test_metaso_integration.py +424 -0
- autocoder/rag/tools/test_metaso_real.py +171 -0
- autocoder/rag/tools/test_web_crawl_tool.py +639 -0
- autocoder/rag/tools/test_web_search_tool.py +509 -0
- autocoder/rag/tools/todo_read_tool.py +202 -0
- autocoder/rag/tools/todo_write_tool.py +412 -0
- autocoder/rag/tools/web_crawl_tool.py +634 -0
- autocoder/rag/tools/web_search_tool.py +558 -0
- autocoder/rag/tools/web_tools_example.py +119 -0
- autocoder/rag/types.py +16 -0
- autocoder/rag/variable_holder.py +4 -2
- autocoder/rags.py +86 -79
- autocoder/regexproject/__init__.py +23 -21
- autocoder/sdk/__init__.py +46 -190
- autocoder/sdk/api.py +370 -0
- autocoder/sdk/async_runner/__init__.py +26 -0
- autocoder/sdk/async_runner/async_executor.py +650 -0
- autocoder/sdk/async_runner/async_handler.py +356 -0
- autocoder/sdk/async_runner/markdown_processor.py +595 -0
- autocoder/sdk/async_runner/task_metadata.py +284 -0
- autocoder/sdk/async_runner/worktree_manager.py +438 -0
- autocoder/sdk/cli/__init__.py +2 -5
- autocoder/sdk/cli/formatters.py +28 -204
- autocoder/sdk/cli/handlers.py +77 -44
- autocoder/sdk/cli/main.py +154 -171
- autocoder/sdk/cli/options.py +95 -22
- autocoder/sdk/constants.py +139 -51
- autocoder/sdk/core/auto_coder_core.py +484 -109
- autocoder/sdk/core/bridge.py +297 -115
- autocoder/sdk/exceptions.py +18 -12
- autocoder/sdk/formatters/__init__.py +19 -0
- autocoder/sdk/formatters/input.py +64 -0
- autocoder/sdk/formatters/output.py +247 -0
- autocoder/sdk/formatters/stream.py +54 -0
- autocoder/sdk/models/__init__.py +6 -5
- autocoder/sdk/models/options.py +55 -18
- autocoder/sdk/utils/formatters.py +27 -195
- autocoder/suffixproject/__init__.py +28 -25
- autocoder/terminal/__init__.py +14 -0
- autocoder/terminal/app.py +454 -0
- autocoder/terminal/args.py +32 -0
- autocoder/terminal/bootstrap.py +178 -0
- autocoder/terminal/command_processor.py +521 -0
- autocoder/terminal/command_registry.py +57 -0
- autocoder/terminal/help.py +97 -0
- autocoder/terminal/tasks/__init__.py +5 -0
- autocoder/terminal/tasks/background.py +77 -0
- autocoder/terminal/tasks/task_event.py +70 -0
- autocoder/terminal/ui/__init__.py +13 -0
- autocoder/terminal/ui/completer.py +268 -0
- autocoder/terminal/ui/keybindings.py +75 -0
- autocoder/terminal/ui/session.py +41 -0
- autocoder/terminal/ui/toolbar.py +64 -0
- autocoder/terminal/utils/__init__.py +13 -0
- autocoder/terminal/utils/errors.py +18 -0
- autocoder/terminal/utils/paths.py +19 -0
- autocoder/terminal/utils/shell.py +43 -0
- autocoder/terminal_v3/__init__.py +10 -0
- autocoder/terminal_v3/app.py +201 -0
- autocoder/terminal_v3/handlers/__init__.py +5 -0
- autocoder/terminal_v3/handlers/command_handler.py +131 -0
- autocoder/terminal_v3/models/__init__.py +6 -0
- autocoder/terminal_v3/models/conversation_buffer.py +214 -0
- autocoder/terminal_v3/models/message.py +50 -0
- autocoder/terminal_v3/models/tool_display.py +247 -0
- autocoder/terminal_v3/ui/__init__.py +7 -0
- autocoder/terminal_v3/ui/keybindings.py +56 -0
- autocoder/terminal_v3/ui/layout.py +141 -0
- autocoder/terminal_v3/ui/styles.py +43 -0
- autocoder/tsproject/__init__.py +23 -23
- autocoder/utils/auto_coder_utils/chat_stream_out.py +1 -1
- autocoder/utils/llms.py +88 -80
- autocoder/utils/math_utils.py +101 -0
- autocoder/utils/model_provider_selector.py +16 -4
- autocoder/utils/operate_config_api.py +33 -5
- autocoder/utils/thread_utils.py +2 -2
- autocoder/version.py +4 -2
- autocoder/workflow_agents/__init__.py +84 -0
- autocoder/workflow_agents/agent.py +143 -0
- autocoder/workflow_agents/exceptions.py +573 -0
- autocoder/workflow_agents/executor.py +665 -0
- autocoder/workflow_agents/loader.py +749 -0
- autocoder/workflow_agents/runner.py +267 -0
- autocoder/workflow_agents/types.py +173 -0
- autocoder/workflow_agents/utils.py +434 -0
- autocoder/workflow_agents/workflow_manager.py +211 -0
- auto_coder-1.0.0.dist-info/METADATA +0 -396
- auto_coder-1.0.0.dist-info/RECORD +0 -442
- auto_coder-1.0.0.dist-info/licenses/LICENSE +0 -201
- autocoder/auto_coder_server.py +0 -672
- autocoder/benchmark.py +0 -138
- autocoder/common/ac_style_command_parser/example.py +0 -7
- autocoder/common/cleaner.py +0 -31
- autocoder/common/command_completer_v2.py +0 -615
- autocoder/common/context_pruner.py +0 -477
- autocoder/common/conversation_pruner.py +0 -132
- autocoder/common/directory_cache/__init__.py +0 -1
- autocoder/common/directory_cache/cache.py +0 -192
- autocoder/common/directory_cache/test_cache.py +0 -190
- autocoder/common/file_checkpoint/examples.py +0 -217
- autocoder/common/llm_friendly_package_example.py +0 -138
- autocoder/common/llm_friendly_package_test.py +0 -63
- autocoder/common/pull_requests/test_module.py +0 -1
- autocoder/common/rulefiles/autocoderrules_utils.py +0 -484
- autocoder/common/text.py +0 -30
- autocoder/common/v2/agent/agentic_edit_tools/list_package_info_tool_resolver.py +0 -42
- autocoder/common/v2/agent/agentic_edit_tools/test_execute_command_tool_resolver.py +0 -70
- autocoder/common/v2/agent/agentic_edit_tools/test_search_files_tool_resolver.py +0 -163
- autocoder/common/v2/agent/agentic_tool_display.py +0 -183
- autocoder/plugins/dynamic_completion_example.py +0 -148
- autocoder/plugins/sample_plugin.py +0 -160
- autocoder/sdk/cli/__main__.py +0 -26
- autocoder/sdk/cli/completion_wrapper.py +0 -38
- autocoder/sdk/cli/install_completion.py +0 -301
- autocoder/sdk/models/messages.py +0 -209
- autocoder/sdk/session/__init__.py +0 -32
- autocoder/sdk/session/session.py +0 -106
- autocoder/sdk/session/session_manager.py +0 -56
- {auto_coder-1.0.0.dist-info → auto_coder-2.0.1.dist-info}/top_level.txt +0 -0
- /autocoder/{sdk/example.py → common/agent_query_queue/__init__.py} +0 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Shell Commands Module
|
|
3
|
+
|
|
4
|
+
This module provides comprehensive shell command execution capabilities
|
|
5
|
+
including timeout control, process management, error recovery, and
|
|
6
|
+
interactive session management with process type switching support.
|
|
7
|
+
|
|
8
|
+
Main Components:
|
|
9
|
+
- CommandExecutor: Main command execution interface
|
|
10
|
+
- TimeoutConfig, TimeoutManager: Timeout control system
|
|
11
|
+
- ProcessManager: Process lifecycle management
|
|
12
|
+
- InteractiveCommandExecutor: Interactive command execution
|
|
13
|
+
- InteractiveProcess: Standard subprocess-based interactive process
|
|
14
|
+
- InteractivePexpectProcess: pexpect-based interactive process
|
|
15
|
+
- InteractiveSessionManager: Session management with process type switching
|
|
16
|
+
- Error recovery and process cleanup utilities
|
|
17
|
+
|
|
18
|
+
Usage:
|
|
19
|
+
# Basic command execution
|
|
20
|
+
from autocoder.common.shell_commands import CommandExecutor
|
|
21
|
+
executor = CommandExecutor()
|
|
22
|
+
result = executor.execute_command("ls -la")
|
|
23
|
+
|
|
24
|
+
# Interactive sessions with process type control
|
|
25
|
+
from autocoder.common.shell_commands import get_session_manager
|
|
26
|
+
manager = get_session_manager()
|
|
27
|
+
|
|
28
|
+
# Auto-select process type
|
|
29
|
+
result = manager.create_session("python3")
|
|
30
|
+
|
|
31
|
+
# Explicit process type selection
|
|
32
|
+
result = manager.create_session("python3", use_pexpect=True)
|
|
33
|
+
result = manager.create_session("echo test", use_pexpect=False)
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
# Core command execution
|
|
37
|
+
from .command_executor import (
|
|
38
|
+
CommandExecutor,
|
|
39
|
+
execute_command,
|
|
40
|
+
execute_command_generator,
|
|
41
|
+
execute_command_background,
|
|
42
|
+
execute_commands,
|
|
43
|
+
get_background_processes,
|
|
44
|
+
get_background_process_info,
|
|
45
|
+
cleanup_background_process
|
|
46
|
+
)
|
|
47
|
+
from .exceptions import (
|
|
48
|
+
CommandExecutionError,
|
|
49
|
+
CommandTimeoutError,
|
|
50
|
+
ProcessCleanupError
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
# Timeout management
|
|
54
|
+
from .timeout_config import TimeoutConfig
|
|
55
|
+
from .timeout_manager import TimeoutManager
|
|
56
|
+
|
|
57
|
+
# Process management
|
|
58
|
+
from .process_manager import ProcessManager
|
|
59
|
+
from .process_cleanup import cleanup_process_tree
|
|
60
|
+
|
|
61
|
+
# Interactive execution
|
|
62
|
+
from .interactive_executor import (
|
|
63
|
+
InteractiveCommandExecutor,
|
|
64
|
+
InteractiveSession,
|
|
65
|
+
execute_interactive,
|
|
66
|
+
create_interactive_shell
|
|
67
|
+
)
|
|
68
|
+
from .interactive_process import InteractiveProcess
|
|
69
|
+
|
|
70
|
+
# pexpect-based execution
|
|
71
|
+
from .interactive_pexpect_process import (
|
|
72
|
+
InteractivePexpectProcess,
|
|
73
|
+
PEXPECT_AVAILABLE
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
# Enhanced session management
|
|
77
|
+
from .interactive_session_manager import (
|
|
78
|
+
InteractiveSessionManager,
|
|
79
|
+
EnhancedSessionHandle,
|
|
80
|
+
ProcessType,
|
|
81
|
+
ToolResult,
|
|
82
|
+
get_session_manager,
|
|
83
|
+
clean_terminal_output
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# Error recovery
|
|
87
|
+
from .error_recovery import ErrorRecoveryManager
|
|
88
|
+
|
|
89
|
+
# Monitoring
|
|
90
|
+
from .monitoring import CommandExecutionLogger, PerformanceMonitor
|
|
91
|
+
from .background_process_notifier import (
|
|
92
|
+
BackgroundProcessNotifier,
|
|
93
|
+
get_background_process_notifier,
|
|
94
|
+
AsyncTaskMessage,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
# Version information
|
|
98
|
+
__version__ = "1.2.0"
|
|
99
|
+
|
|
100
|
+
# Convenience exports
|
|
101
|
+
__all__ = [
|
|
102
|
+
# Core execution
|
|
103
|
+
"CommandExecutor",
|
|
104
|
+
"execute_command",
|
|
105
|
+
"execute_command_generator",
|
|
106
|
+
"execute_command_background",
|
|
107
|
+
"execute_commands",
|
|
108
|
+
"get_background_processes",
|
|
109
|
+
"get_background_process_info",
|
|
110
|
+
"cleanup_background_process",
|
|
111
|
+
|
|
112
|
+
# Exceptions
|
|
113
|
+
"CommandExecutionError",
|
|
114
|
+
"CommandTimeoutError",
|
|
115
|
+
"ProcessCleanupError",
|
|
116
|
+
|
|
117
|
+
# Timeout management
|
|
118
|
+
"TimeoutConfig",
|
|
119
|
+
"TimeoutManager",
|
|
120
|
+
|
|
121
|
+
# Process management
|
|
122
|
+
"ProcessManager",
|
|
123
|
+
"cleanup_process_tree",
|
|
124
|
+
|
|
125
|
+
# Interactive execution
|
|
126
|
+
"InteractiveCommandExecutor",
|
|
127
|
+
"InteractiveSession",
|
|
128
|
+
"InteractiveProcess",
|
|
129
|
+
"execute_interactive",
|
|
130
|
+
"create_interactive_shell",
|
|
131
|
+
|
|
132
|
+
# pexpect support
|
|
133
|
+
"InteractivePexpectProcess",
|
|
134
|
+
"PEXPECT_AVAILABLE",
|
|
135
|
+
|
|
136
|
+
# Enhanced session management
|
|
137
|
+
"InteractiveSessionManager",
|
|
138
|
+
"EnhancedSessionHandle",
|
|
139
|
+
"ProcessType",
|
|
140
|
+
"ToolResult",
|
|
141
|
+
"get_session_manager",
|
|
142
|
+
"clean_terminal_output",
|
|
143
|
+
|
|
144
|
+
# Error recovery
|
|
145
|
+
"ErrorRecoveryManager",
|
|
146
|
+
|
|
147
|
+
# Monitoring
|
|
148
|
+
"CommandExecutionLogger",
|
|
149
|
+
"PerformanceMonitor",
|
|
150
|
+
# Background notifier
|
|
151
|
+
"BackgroundProcessNotifier",
|
|
152
|
+
"get_background_process_notifier",
|
|
153
|
+
"AsyncTaskMessage",
|
|
154
|
+
]
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def get_available_process_types():
|
|
158
|
+
"""
|
|
159
|
+
Get list of available process types.
|
|
160
|
+
|
|
161
|
+
Returns:
|
|
162
|
+
dict: Available process types with availability status
|
|
163
|
+
"""
|
|
164
|
+
return {
|
|
165
|
+
ProcessType.STANDARD: True,
|
|
166
|
+
ProcessType.PEXPECT: PEXPECT_AVAILABLE
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def create_interactive_session(
|
|
171
|
+
command: str,
|
|
172
|
+
process_type: str = "auto",
|
|
173
|
+
**kwargs
|
|
174
|
+
):
|
|
175
|
+
"""
|
|
176
|
+
Convenience function to create an interactive session.
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
command: Command to execute
|
|
180
|
+
process_type: "auto", "standard", "pexpect"
|
|
181
|
+
**kwargs: Additional session arguments
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
ToolResult with session information
|
|
185
|
+
"""
|
|
186
|
+
manager = get_session_manager()
|
|
187
|
+
|
|
188
|
+
if process_type == "auto":
|
|
189
|
+
use_pexpect = None
|
|
190
|
+
elif process_type == ProcessType.PEXPECT:
|
|
191
|
+
use_pexpect = True
|
|
192
|
+
elif process_type == ProcessType.STANDARD:
|
|
193
|
+
use_pexpect = False
|
|
194
|
+
else:
|
|
195
|
+
raise ValueError(f"Invalid process type: {process_type}")
|
|
196
|
+
|
|
197
|
+
return manager.create_session(command, use_pexpect=use_pexpect, **kwargs)
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
"""
|
|
2
|
+
BackgroundProcessNotifier
|
|
3
|
+
|
|
4
|
+
A lightweight in-memory notifier that monitors background processes and
|
|
5
|
+
produces async completion messages correlated by conversation_id.
|
|
6
|
+
|
|
7
|
+
It periodically polls the global ProcessManager's background processes,
|
|
8
|
+
detects transitions from running to completed, collects final outputs,
|
|
9
|
+
and enqueues AsyncTaskMessage items keyed by conversation_id for consumers
|
|
10
|
+
to poll.
|
|
11
|
+
|
|
12
|
+
This module intentionally does not depend on the events/ module.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import os
|
|
18
|
+
import threading
|
|
19
|
+
import time
|
|
20
|
+
import uuid
|
|
21
|
+
from collections import defaultdict, deque
|
|
22
|
+
from dataclasses import dataclass
|
|
23
|
+
from typing import Deque, Dict, List, Optional, Tuple
|
|
24
|
+
|
|
25
|
+
from loguru import logger
|
|
26
|
+
|
|
27
|
+
# Reuse the global background process manager accessor to avoid divergence
|
|
28
|
+
from .command_executor import get_background_processes, get_background_process_info
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass
|
|
32
|
+
class BackgroundTaskRegistration:
|
|
33
|
+
conversation_id: str
|
|
34
|
+
pid: int
|
|
35
|
+
tool_name: str
|
|
36
|
+
command: str
|
|
37
|
+
cwd: Optional[str]
|
|
38
|
+
agent_name: Optional[str]
|
|
39
|
+
task: Optional[str]
|
|
40
|
+
task_id: str
|
|
41
|
+
start_time: float
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass
|
|
45
|
+
class AsyncTaskMessage:
|
|
46
|
+
conversation_id: str
|
|
47
|
+
task_id: str
|
|
48
|
+
pid: int
|
|
49
|
+
tool_name: str
|
|
50
|
+
status: str # "completed" | "failed"
|
|
51
|
+
exit_code: Optional[int]
|
|
52
|
+
duration_sec: Optional[float]
|
|
53
|
+
command: str
|
|
54
|
+
cwd: Optional[str]
|
|
55
|
+
agent_name: Optional[str]
|
|
56
|
+
task: Optional[str]
|
|
57
|
+
output_tail: Optional[str]
|
|
58
|
+
error_tail: Optional[str]
|
|
59
|
+
completed_at: float
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class BackgroundProcessNotifier:
|
|
63
|
+
"""
|
|
64
|
+
Singleton notifier for background process completion correlated by conversation_id.
|
|
65
|
+
|
|
66
|
+
Public API:
|
|
67
|
+
- get_instance()
|
|
68
|
+
- register_process(...)
|
|
69
|
+
- poll_messages(conversation_id, max_items=32)
|
|
70
|
+
- has_messages(conversation_id)
|
|
71
|
+
- set_options(...)
|
|
72
|
+
- stop()
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
_instance: Optional["BackgroundProcessNotifier"] = None
|
|
76
|
+
_instance_lock = threading.Lock()
|
|
77
|
+
|
|
78
|
+
@classmethod
|
|
79
|
+
def get_instance(cls) -> "BackgroundProcessNotifier":
|
|
80
|
+
if cls._instance is None:
|
|
81
|
+
with cls._instance_lock:
|
|
82
|
+
if cls._instance is None:
|
|
83
|
+
cls._instance = BackgroundProcessNotifier()
|
|
84
|
+
return cls._instance
|
|
85
|
+
|
|
86
|
+
def __init__(self) -> None:
|
|
87
|
+
# Thread-safety primitives
|
|
88
|
+
self._lock = threading.RLock()
|
|
89
|
+
self._stop_event = threading.Event()
|
|
90
|
+
|
|
91
|
+
# Configurable options
|
|
92
|
+
self._poll_interval_sec: float = 0.5
|
|
93
|
+
self._max_output_bytes: int = 16 * 1024
|
|
94
|
+
self._max_output_lines: int = 200
|
|
95
|
+
|
|
96
|
+
# State
|
|
97
|
+
# Use (pid, start_time) as stable key to avoid PID reuse collisions
|
|
98
|
+
self._registrations: Dict[Tuple[int, float], BackgroundTaskRegistration] = {}
|
|
99
|
+
self._pid_to_key: Dict[int, Tuple[int, float]] = {}
|
|
100
|
+
self._reported: set[Tuple[int, float]] = set()
|
|
101
|
+
self._pending_messages: Dict[str, Deque[AsyncTaskMessage]] = defaultdict(deque)
|
|
102
|
+
|
|
103
|
+
# Start monitor thread
|
|
104
|
+
self._monitor_thread = threading.Thread(
|
|
105
|
+
target=self._monitor_loop, name="BackgroundProcessNotifierThread", daemon=True
|
|
106
|
+
)
|
|
107
|
+
self._monitor_thread.start()
|
|
108
|
+
|
|
109
|
+
# ---------------------------- Public API ----------------------------
|
|
110
|
+
def set_options(
|
|
111
|
+
self,
|
|
112
|
+
poll_interval_sec: Optional[float] = None,
|
|
113
|
+
max_output_bytes: Optional[int] = None,
|
|
114
|
+
max_output_lines: Optional[int] = None,
|
|
115
|
+
) -> None:
|
|
116
|
+
with self._lock:
|
|
117
|
+
if poll_interval_sec is not None and poll_interval_sec > 0:
|
|
118
|
+
self._poll_interval_sec = float(poll_interval_sec)
|
|
119
|
+
if max_output_bytes is not None and max_output_bytes > 0:
|
|
120
|
+
self._max_output_bytes = int(max_output_bytes)
|
|
121
|
+
if max_output_lines is not None and max_output_lines > 0:
|
|
122
|
+
self._max_output_lines = int(max_output_lines)
|
|
123
|
+
|
|
124
|
+
def register_process(
|
|
125
|
+
self,
|
|
126
|
+
*,
|
|
127
|
+
conversation_id: str,
|
|
128
|
+
pid: int,
|
|
129
|
+
tool_name: str,
|
|
130
|
+
command: str,
|
|
131
|
+
cwd: Optional[str] = None,
|
|
132
|
+
agent_name: Optional[str] = None,
|
|
133
|
+
task: Optional[str] = None,
|
|
134
|
+
) -> str:
|
|
135
|
+
"""
|
|
136
|
+
Register a background process to be monitored.
|
|
137
|
+
Returns a generated task_id string.
|
|
138
|
+
"""
|
|
139
|
+
start_time = self._get_process_start_time(pid)
|
|
140
|
+
task_id = str(uuid.uuid4())
|
|
141
|
+
registration = BackgroundTaskRegistration(
|
|
142
|
+
conversation_id=conversation_id,
|
|
143
|
+
pid=pid,
|
|
144
|
+
tool_name=tool_name,
|
|
145
|
+
command=command,
|
|
146
|
+
cwd=cwd,
|
|
147
|
+
agent_name=agent_name,
|
|
148
|
+
task=task,
|
|
149
|
+
task_id=task_id,
|
|
150
|
+
start_time=start_time,
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
key = (pid, start_time)
|
|
154
|
+
with self._lock:
|
|
155
|
+
self._registrations[key] = registration
|
|
156
|
+
self._pid_to_key[pid] = key
|
|
157
|
+
|
|
158
|
+
logger.info(
|
|
159
|
+
f"BackgroundProcessNotifier: registered pid={pid} tool={tool_name} conv={conversation_id} task_id={task_id}"
|
|
160
|
+
)
|
|
161
|
+
return task_id
|
|
162
|
+
|
|
163
|
+
def poll_messages(self, conversation_id: str, max_items: int = 32) -> List[AsyncTaskMessage]:
|
|
164
|
+
with self._lock:
|
|
165
|
+
q = self._pending_messages.get(conversation_id)
|
|
166
|
+
if not q:
|
|
167
|
+
return []
|
|
168
|
+
items: List[AsyncTaskMessage] = []
|
|
169
|
+
for _ in range(min(max_items, len(q))):
|
|
170
|
+
items.append(q.popleft())
|
|
171
|
+
# Clean up empty deque entries
|
|
172
|
+
if not q:
|
|
173
|
+
self._pending_messages.pop(conversation_id, None)
|
|
174
|
+
return items
|
|
175
|
+
|
|
176
|
+
def has_messages(self, conversation_id: str) -> bool:
|
|
177
|
+
with self._lock:
|
|
178
|
+
q = self._pending_messages.get(conversation_id)
|
|
179
|
+
return bool(q and len(q) > 0)
|
|
180
|
+
|
|
181
|
+
def stop(self) -> None:
|
|
182
|
+
self._stop_event.set()
|
|
183
|
+
if self._monitor_thread.is_alive():
|
|
184
|
+
self._monitor_thread.join(timeout=2.0)
|
|
185
|
+
|
|
186
|
+
# ---------------------------- Internal ----------------------------
|
|
187
|
+
def _monitor_loop(self) -> None:
|
|
188
|
+
while not self._stop_event.is_set():
|
|
189
|
+
try:
|
|
190
|
+
self._scan_background_processes()
|
|
191
|
+
except Exception as e:
|
|
192
|
+
logger.warning(f"BackgroundProcessNotifier monitor error: {e}")
|
|
193
|
+
finally:
|
|
194
|
+
self._stop_event.wait(self._poll_interval_sec)
|
|
195
|
+
|
|
196
|
+
def _scan_background_processes(self) -> None:
|
|
197
|
+
bg = get_background_processes()
|
|
198
|
+
if not bg:
|
|
199
|
+
return
|
|
200
|
+
|
|
201
|
+
# Snapshot keys for iteration under lock safety
|
|
202
|
+
with self._lock:
|
|
203
|
+
registrations_items = list(self._registrations.items())
|
|
204
|
+
|
|
205
|
+
for key, reg in registrations_items:
|
|
206
|
+
pid, reg_start_time = key
|
|
207
|
+
info = bg.get(pid)
|
|
208
|
+
if not info:
|
|
209
|
+
# Might have been cleaned up already
|
|
210
|
+
continue
|
|
211
|
+
|
|
212
|
+
status = info.get("status")
|
|
213
|
+
if status != "completed":
|
|
214
|
+
continue
|
|
215
|
+
|
|
216
|
+
# Ensure this completion hasn't been reported yet
|
|
217
|
+
with self._lock:
|
|
218
|
+
if key in self._reported:
|
|
219
|
+
continue
|
|
220
|
+
|
|
221
|
+
# Build message
|
|
222
|
+
exit_code = info.get("exit_code")
|
|
223
|
+
end_time = info.get("end_time", time.time())
|
|
224
|
+
start_time = info.get("start_time", reg_start_time)
|
|
225
|
+
duration = (end_time - start_time) if (end_time and start_time) else None
|
|
226
|
+
|
|
227
|
+
output_tail, error_tail = self._read_process_output_tails(info)
|
|
228
|
+
|
|
229
|
+
message = AsyncTaskMessage(
|
|
230
|
+
conversation_id=reg.conversation_id,
|
|
231
|
+
task_id=reg.task_id,
|
|
232
|
+
pid=pid,
|
|
233
|
+
tool_name=reg.tool_name,
|
|
234
|
+
status="failed" if (exit_code is not None and exit_code != 0) else "completed",
|
|
235
|
+
exit_code=exit_code,
|
|
236
|
+
duration_sec=duration,
|
|
237
|
+
command=reg.command,
|
|
238
|
+
cwd=reg.cwd,
|
|
239
|
+
agent_name=reg.agent_name,
|
|
240
|
+
task=reg.task,
|
|
241
|
+
output_tail=output_tail,
|
|
242
|
+
error_tail=error_tail,
|
|
243
|
+
completed_at=end_time,
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
with self._lock:
|
|
247
|
+
self._pending_messages[reg.conversation_id].append(message)
|
|
248
|
+
self._reported.add(key)
|
|
249
|
+
# Remove registration after reporting
|
|
250
|
+
self._registrations.pop(key, None)
|
|
251
|
+
# Keep pid_to_key consistent
|
|
252
|
+
old_key = self._pid_to_key.get(pid)
|
|
253
|
+
if old_key == key:
|
|
254
|
+
self._pid_to_key.pop(pid, None)
|
|
255
|
+
|
|
256
|
+
logger.info(
|
|
257
|
+
f"BackgroundProcessNotifier: reported completion for pid={pid} task_id={reg.task_id} conv={reg.conversation_id} exit_code={exit_code}"
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
def _read_process_output_tails(self, info: Dict) -> Tuple[Optional[str], Optional[str]]:
|
|
261
|
+
"""
|
|
262
|
+
Read stdout/stderr tails from files in .auto-coder/backgrounds directory.
|
|
263
|
+
Files are named as {process_uniq_id}.out and {process_uniq_id}.err.
|
|
264
|
+
"""
|
|
265
|
+
# Get process_uniq_id
|
|
266
|
+
process_uniq_id = info.get("process_uniq_id")
|
|
267
|
+
|
|
268
|
+
if not process_uniq_id:
|
|
269
|
+
return None, None
|
|
270
|
+
|
|
271
|
+
# Resolve backgrounds directory relative to the process working directory if provided,
|
|
272
|
+
# otherwise fall back to current working directory. This keeps notifier robust when
|
|
273
|
+
# called from different CWDs.
|
|
274
|
+
cwd = info.get("cwd") or info.get("working_directory")
|
|
275
|
+
base_dir = cwd if isinstance(cwd, str) and len(cwd) > 0 else os.getcwd()
|
|
276
|
+
backgrounds_dir = os.path.join(base_dir, '.auto-coder', 'backgrounds')
|
|
277
|
+
stdout_file = os.path.join(backgrounds_dir, f"{process_uniq_id}.out")
|
|
278
|
+
stderr_file = os.path.join(backgrounds_dir, f"{process_uniq_id}.err")
|
|
279
|
+
|
|
280
|
+
out_tail = self._read_file_tail(stdout_file)
|
|
281
|
+
err_tail = self._read_file_tail(stderr_file)
|
|
282
|
+
|
|
283
|
+
return out_tail, err_tail
|
|
284
|
+
|
|
285
|
+
def _read_file_tail(self, filepath: str) -> Optional[str]:
|
|
286
|
+
"""
|
|
287
|
+
Read the tail of a file according to configured limits.
|
|
288
|
+
Returns None if file doesn't exist or can't be read.
|
|
289
|
+
"""
|
|
290
|
+
if not os.path.exists(filepath):
|
|
291
|
+
return None
|
|
292
|
+
|
|
293
|
+
try:
|
|
294
|
+
# Get file size
|
|
295
|
+
file_size = os.path.getsize(filepath)
|
|
296
|
+
if file_size == 0:
|
|
297
|
+
return ""
|
|
298
|
+
|
|
299
|
+
with open(filepath, 'rb') as f:
|
|
300
|
+
# Read from the end of file
|
|
301
|
+
if file_size > self._max_output_bytes:
|
|
302
|
+
# Seek to position that gives us approximately max_output_bytes
|
|
303
|
+
f.seek(-self._max_output_bytes, os.SEEK_END)
|
|
304
|
+
# Read to end of current line to avoid partial lines
|
|
305
|
+
f.readline() # Skip partial line
|
|
306
|
+
data = f.read()
|
|
307
|
+
else:
|
|
308
|
+
# Read entire file if it's small enough
|
|
309
|
+
data = f.read()
|
|
310
|
+
|
|
311
|
+
# Decode and process
|
|
312
|
+
text = data.decode('utf-8', errors='replace')
|
|
313
|
+
return self._tail_text(text)
|
|
314
|
+
|
|
315
|
+
except Exception as e:
|
|
316
|
+
logger.warning(f"Failed to read tail from {filepath}: {e}")
|
|
317
|
+
return None
|
|
318
|
+
|
|
319
|
+
def _tail_text(self, text: str) -> str:
|
|
320
|
+
# First bound by bytes length, then by line count
|
|
321
|
+
if not text:
|
|
322
|
+
return ""
|
|
323
|
+
|
|
324
|
+
# Trim by bytes (approx via UTF-8 encoding)
|
|
325
|
+
data = text.encode("utf-8", errors="replace")
|
|
326
|
+
if len(data) > self._max_output_bytes:
|
|
327
|
+
data = data[-self._max_output_bytes :]
|
|
328
|
+
trimmed = data.decode("utf-8", errors="replace")
|
|
329
|
+
|
|
330
|
+
# Then trim by lines
|
|
331
|
+
lines = trimmed.splitlines()
|
|
332
|
+
if len(lines) > self._max_output_lines:
|
|
333
|
+
lines = lines[-self._max_output_lines :]
|
|
334
|
+
return "\n".join(lines)
|
|
335
|
+
|
|
336
|
+
def _get_process_start_time(self, pid: int) -> float:
|
|
337
|
+
info = get_background_process_info(pid)
|
|
338
|
+
if info and "start_time" in info and isinstance(info["start_time"], (int, float)):
|
|
339
|
+
return float(info["start_time"])
|
|
340
|
+
return time.time()
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
def get_background_process_notifier() -> BackgroundProcessNotifier:
|
|
344
|
+
return BackgroundProcessNotifier.get_instance()
|
|
345
|
+
|
|
346
|
+
|