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
autocoder/auto_coder_runner.py
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
from
|
|
1
|
+
from autocoder.common.project_scanner.compat import create_scanner_functions
|
|
2
2
|
from rich.console import Console
|
|
3
3
|
from rich.panel import Panel
|
|
4
4
|
from prompt_toolkit.formatted_text import HTML
|
|
5
|
-
from prompt_toolkit.shortcuts import radiolist_dialog
|
|
6
5
|
from prompt_toolkit import prompt
|
|
7
6
|
import os
|
|
8
7
|
import yaml
|
|
@@ -10,73 +9,97 @@ import json
|
|
|
10
9
|
import sys
|
|
11
10
|
import io
|
|
12
11
|
import uuid
|
|
13
|
-
import glob
|
|
14
12
|
import time
|
|
15
|
-
import
|
|
16
|
-
import
|
|
13
|
+
import byzerllm
|
|
14
|
+
import subprocess
|
|
17
15
|
from contextlib import contextmanager
|
|
18
16
|
from typing import List, Dict, Any, Optional
|
|
19
17
|
from autocoder.common import AutoCoderArgs
|
|
18
|
+
from autocoder.common.autocoderargs_parser import AutoCoderArgsParser
|
|
20
19
|
from pydantic import BaseModel
|
|
21
|
-
from autocoder.common.action_yml_file_manager import ActionYmlFileManager
|
|
22
20
|
from autocoder.common.result_manager import ResultManager
|
|
23
21
|
from autocoder.version import __version__
|
|
24
22
|
from autocoder.auto_coder import main as auto_coder_main
|
|
25
23
|
from autocoder.utils import get_last_yaml_file
|
|
26
|
-
from autocoder.commands.auto_command import
|
|
24
|
+
from autocoder.commands.auto_command import (
|
|
25
|
+
CommandAutoTuner,
|
|
26
|
+
AutoCommandRequest,
|
|
27
|
+
CommandConfig,
|
|
28
|
+
MemoryConfig,
|
|
29
|
+
)
|
|
27
30
|
from autocoder.common.v2.agent.agentic_edit import AgenticEditRequest
|
|
28
|
-
from autocoder.common.v2.agent.agentic_edit_types import
|
|
31
|
+
from autocoder.common.v2.agent.agentic_edit_types import (
|
|
32
|
+
AgenticEditConversationConfig,
|
|
33
|
+
ConversationAction,
|
|
34
|
+
)
|
|
35
|
+
from autocoder.common.conversations.get_conversation_manager import (
|
|
36
|
+
get_conversation_manager,
|
|
37
|
+
)
|
|
29
38
|
from autocoder.index.symbols_utils import (
|
|
30
|
-
extract_symbols,
|
|
31
39
|
SymbolType,
|
|
32
40
|
)
|
|
33
41
|
import platform
|
|
34
|
-
import subprocess
|
|
35
|
-
from rich.console import Console
|
|
36
42
|
from rich.panel import Panel
|
|
37
43
|
from rich.table import Table
|
|
38
|
-
from
|
|
39
|
-
|
|
40
|
-
from rich.live import Live
|
|
44
|
+
from copy import deepcopy
|
|
45
|
+
|
|
41
46
|
from rich.markdown import Markdown
|
|
42
47
|
from byzerllm.utils.nontext import Image
|
|
43
|
-
import
|
|
48
|
+
from autocoder.inner.agentic import RunAgentic
|
|
49
|
+
|
|
50
|
+
# 延迟导入git模块以避免启动异常
|
|
51
|
+
try:
|
|
52
|
+
import git
|
|
53
|
+
|
|
54
|
+
GIT_AVAILABLE = True
|
|
55
|
+
except ImportError:
|
|
56
|
+
from loguru import logger
|
|
57
|
+
|
|
58
|
+
logger.warning("Git module not available. Some git features will be disabled.")
|
|
59
|
+
GIT_AVAILABLE = False
|
|
60
|
+
git = None
|
|
44
61
|
from autocoder.common import git_utils
|
|
45
|
-
from autocoder.chat_auto_coder_lang import get_message,get_message_with_format
|
|
62
|
+
from autocoder.chat_auto_coder_lang import get_message, get_message_with_format
|
|
46
63
|
from autocoder.agent.auto_guess_query import AutoGuessQuery
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
import
|
|
53
|
-
from
|
|
54
|
-
from autocoder.common.
|
|
55
|
-
from
|
|
56
|
-
import
|
|
64
|
+
|
|
65
|
+
# Do not remove these imports, they are exported to other modules e.g. chat_auto_coder.py
|
|
66
|
+
from autocoder.common.mcp_tools.server import get_mcp_server
|
|
67
|
+
from autocoder.common.memory_manager import get_global_memory_file_paths
|
|
68
|
+
|
|
69
|
+
from rich.panel import Panel
|
|
70
|
+
from rich.table import Table
|
|
71
|
+
from autocoder.common.international import get_message, get_message_with_format
|
|
72
|
+
from rich.prompt import Confirm
|
|
73
|
+
from autocoder.common.printer import Printer
|
|
57
74
|
from autocoder.utils.llms import get_single_llm
|
|
58
|
-
import
|
|
59
|
-
import pkg_resources
|
|
75
|
+
import importlib.resources as resources
|
|
60
76
|
from autocoder.common.printer import Printer
|
|
61
|
-
from autocoder.
|
|
62
|
-
from autocoder.memory.active_context_manager import ActiveContextManager
|
|
63
|
-
from autocoder.common.command_completer import CommandCompleter,FileSystemModel as CCFileSystemModel,MemoryConfig as CCMemoryModel
|
|
77
|
+
from autocoder.common.command_completer import MemoryConfig as CCMemoryModel
|
|
64
78
|
from autocoder.common.conf_validator import ConfigValidator
|
|
65
79
|
from autocoder.common.ac_style_command_parser import parse_query
|
|
66
80
|
from loguru import logger as global_logger
|
|
67
81
|
from autocoder.utils.project_structure import EnhancedFileAnalyzer
|
|
68
|
-
from autocoder.common import
|
|
82
|
+
from autocoder.common import SourceCode
|
|
69
83
|
from autocoder.common.file_monitor import FileMonitor
|
|
70
|
-
from filelock import FileLock
|
|
71
84
|
from autocoder.common.command_file_manager import CommandManager
|
|
72
|
-
from autocoder.common.v2.agent.runner import
|
|
85
|
+
from autocoder.common.v2.agent.runner import (
|
|
86
|
+
SdkRunner,
|
|
87
|
+
TerminalRunner,
|
|
88
|
+
FileBasedEventRunner,
|
|
89
|
+
)
|
|
90
|
+
from autocoder.completer import CommandCompleterV2
|
|
91
|
+
from autocoder.common.core_config import get_memory_manager, load_memory as _load_memory
|
|
92
|
+
from autocoder.common.global_cancel import global_cancel
|
|
93
|
+
|
|
94
|
+
# 对外API,用于第三方集成 auto-coder 使用。
|
|
95
|
+
|
|
73
96
|
|
|
74
|
-
## 对外API,用于第三方集成 auto-coder 使用。
|
|
75
97
|
class SymbolItem(BaseModel):
|
|
76
98
|
symbol_name: str
|
|
77
99
|
symbol_type: SymbolType
|
|
78
100
|
file_name: str
|
|
79
101
|
|
|
102
|
+
|
|
80
103
|
class InitializeSystemRequest(BaseModel):
|
|
81
104
|
product_mode: str
|
|
82
105
|
skip_provider_selection: bool
|
|
@@ -92,20 +115,45 @@ if platform.system() == "Windows":
|
|
|
92
115
|
init()
|
|
93
116
|
|
|
94
117
|
|
|
95
|
-
memory
|
|
96
|
-
"conversation": [],
|
|
97
|
-
"current_files": {"files": [], "groups": {}},
|
|
98
|
-
"conf": {},
|
|
99
|
-
"exclude_dirs": [],
|
|
100
|
-
"mode": "auto_detect", # 新增mode字段,默认为 auto_detect 模式
|
|
101
|
-
}
|
|
102
|
-
|
|
118
|
+
# Initialize memory and project root
|
|
103
119
|
project_root = os.getcwd()
|
|
104
120
|
|
|
121
|
+
# Initialize memory manager with project root
|
|
122
|
+
_memory_manager = get_memory_manager(project_root)
|
|
123
|
+
|
|
124
|
+
# Wrapper functions to sync global memory variable
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def save_memory():
|
|
128
|
+
"""Save memory - compatibility function (no-op since MemoryManager handles persistence)"""
|
|
129
|
+
# This function is kept for backward compatibility but does nothing
|
|
130
|
+
# since MemoryManager automatically handles persistence
|
|
131
|
+
raise NotImplementedError(
|
|
132
|
+
"save_memory is not supported anymore, please use autocoder.common.core_config.memory_manager instead."
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def load_memory():
|
|
137
|
+
"""Load memory using MemoryManager"""
|
|
138
|
+
return _load_memory()
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def get_memory():
|
|
142
|
+
"""Get current memory"""
|
|
143
|
+
return load_memory()
|
|
105
144
|
|
|
106
|
-
base_persist_dir = os.path.join(project_root,".auto-coder", "plugins", "chat-auto-coder")
|
|
107
145
|
|
|
108
|
-
|
|
146
|
+
# Compatibility: base_persist_dir is now managed by memory manager
|
|
147
|
+
base_persist_dir = _memory_manager.base_persist_dir
|
|
148
|
+
|
|
149
|
+
defaut_exclude_dirs = [
|
|
150
|
+
".git",
|
|
151
|
+
"node_modules",
|
|
152
|
+
"dist",
|
|
153
|
+
"build",
|
|
154
|
+
"__pycache__",
|
|
155
|
+
".auto-coder",
|
|
156
|
+
]
|
|
109
157
|
|
|
110
158
|
commands = [
|
|
111
159
|
"/add_files",
|
|
@@ -122,7 +170,7 @@ commands = [
|
|
|
122
170
|
"/index/build",
|
|
123
171
|
"/index/export",
|
|
124
172
|
"/index/import",
|
|
125
|
-
"/exclude_files",
|
|
173
|
+
"/exclude_files",
|
|
126
174
|
"/help",
|
|
127
175
|
"/shell",
|
|
128
176
|
"/voice_input",
|
|
@@ -137,21 +185,66 @@ commands = [
|
|
|
137
185
|
"/conf/export",
|
|
138
186
|
"/conf/import",
|
|
139
187
|
"/exclude_dirs",
|
|
188
|
+
"/queue",
|
|
189
|
+
"/workflow"
|
|
140
190
|
]
|
|
141
191
|
|
|
192
|
+
|
|
142
193
|
def load_tokenizer():
|
|
143
194
|
from autocoder.rag.variable_holder import VariableHolder
|
|
144
|
-
from tokenizers import Tokenizer
|
|
195
|
+
from tokenizers import Tokenizer
|
|
196
|
+
|
|
145
197
|
try:
|
|
146
|
-
tokenizer_path =
|
|
147
|
-
"autocoder", "data/tokenizer.json"
|
|
148
|
-
)
|
|
198
|
+
tokenizer_path = str(resources.files("autocoder") / "data" / "tokenizer.json")
|
|
149
199
|
VariableHolder.TOKENIZER_PATH = tokenizer_path
|
|
150
200
|
VariableHolder.TOKENIZER_MODEL = Tokenizer.from_file(tokenizer_path)
|
|
151
201
|
except FileNotFoundError:
|
|
152
202
|
tokenizer_path = None
|
|
153
203
|
|
|
154
204
|
|
|
205
|
+
def configure_logger():
|
|
206
|
+
# 设置日志目录和文件
|
|
207
|
+
log_dir = os.path.join(project_root, ".auto-coder", "logs")
|
|
208
|
+
os.makedirs(log_dir, exist_ok=True)
|
|
209
|
+
log_file = os.path.join(log_dir, "auto-coder.log")
|
|
210
|
+
|
|
211
|
+
# 配置全局日志
|
|
212
|
+
# 默认情况下,所有日志都写入文件
|
|
213
|
+
# 控制台上默认不输出任何日志,除非显式配置
|
|
214
|
+
global_logger.configure(
|
|
215
|
+
handlers=[
|
|
216
|
+
{
|
|
217
|
+
"sink": log_file,
|
|
218
|
+
"level": "INFO",
|
|
219
|
+
"rotation": "10 MB",
|
|
220
|
+
"retention": "1 week",
|
|
221
|
+
"format": "{time:YYYY-MM-DD HH:mm:ss} | {level} | {name} | {message}",
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
"sink": sys.stdout,
|
|
225
|
+
"level": "INFO",
|
|
226
|
+
"format": "{time:YYYY-MM-DD HH:mm:ss} | {name} | {message}",
|
|
227
|
+
# 默认不打印任何日志到控制台
|
|
228
|
+
"filter": lambda record: False,
|
|
229
|
+
},
|
|
230
|
+
]
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def init_singleton_instances():
|
|
235
|
+
# 初始化文件监控系统
|
|
236
|
+
try:
|
|
237
|
+
FileMonitor(project_root).start()
|
|
238
|
+
except Exception as e:
|
|
239
|
+
global_logger.error(f"Failed to start file monitor: {e}")
|
|
240
|
+
global_logger.exception(e)
|
|
241
|
+
|
|
242
|
+
# 初始化忽略文件管理器
|
|
243
|
+
from autocoder.common.ignorefiles.ignore_file_utils import IgnoreFileManager
|
|
244
|
+
|
|
245
|
+
_ = IgnoreFileManager(project_root=project_root)
|
|
246
|
+
|
|
247
|
+
|
|
155
248
|
def configure_project_type():
|
|
156
249
|
from prompt_toolkit.lexers import PygmentsLexer
|
|
157
250
|
from pygments.lexers.markup import MarkdownLexer
|
|
@@ -173,12 +266,10 @@ def configure_project_type():
|
|
|
173
266
|
print_formatted_text(HTML(f"<info>{escape(text)}</info>"), style=style)
|
|
174
267
|
|
|
175
268
|
def print_warning(text):
|
|
176
|
-
print_formatted_text(
|
|
177
|
-
HTML(f"<warning>{escape(text)}</warning>"), style=style)
|
|
269
|
+
print_formatted_text(HTML(f"<warning>{escape(text)}</warning>"), style=style)
|
|
178
270
|
|
|
179
271
|
def print_header(text):
|
|
180
|
-
print_formatted_text(
|
|
181
|
-
HTML(f"<header>{escape(text)}</header>"), style=style)
|
|
272
|
+
print_formatted_text(HTML(f"<header>{escape(text)}</header>"), style=style)
|
|
182
273
|
|
|
183
274
|
print_header(f"\n=== {get_message('project_type_config')} ===\n")
|
|
184
275
|
print_info(get_message("project_type_supports"))
|
|
@@ -188,7 +279,7 @@ def configure_project_type():
|
|
|
188
279
|
print_info(get_message("examples"))
|
|
189
280
|
|
|
190
281
|
print_warning(f"{get_message('default_type')}\n")
|
|
191
|
-
|
|
282
|
+
|
|
192
283
|
extensions = get_all_extensions(project_root) or "py"
|
|
193
284
|
project_type = prompt(
|
|
194
285
|
get_message("enter_project_type"), default=extensions, style=style
|
|
@@ -215,72 +306,27 @@ def get_all_extensions(directory: str = ".") -> str:
|
|
|
215
306
|
target_file="",
|
|
216
307
|
git_url="",
|
|
217
308
|
project_type="",
|
|
218
|
-
conversation_prune_safe_zone_tokens=0
|
|
309
|
+
conversation_prune_safe_zone_tokens=0,
|
|
219
310
|
)
|
|
220
|
-
|
|
311
|
+
|
|
221
312
|
analyzer = EnhancedFileAnalyzer(
|
|
222
313
|
args=args,
|
|
223
314
|
llm=None, # 如果只是获取后缀名,可以不需要LLM
|
|
224
|
-
config=None # 使用默认配置
|
|
315
|
+
config=None, # 使用默认配置
|
|
225
316
|
)
|
|
226
|
-
|
|
317
|
+
|
|
227
318
|
# 获取分析结果
|
|
228
319
|
analysis_result = analyzer.analyze_extensions()
|
|
229
|
-
|
|
320
|
+
|
|
230
321
|
# 合并 code 和 config 的后缀名
|
|
231
322
|
all_extensions = set(analysis_result["code"] + analysis_result["config"])
|
|
232
|
-
|
|
323
|
+
|
|
233
324
|
# 转换为逗号分隔的字符串
|
|
234
325
|
return ",".join(sorted(all_extensions))
|
|
235
326
|
|
|
236
|
-
def configure_logger():
|
|
237
|
-
# 设置日志目录和文件
|
|
238
|
-
log_dir = os.path.join(project_root, ".auto-coder", "logs")
|
|
239
|
-
os.makedirs(log_dir, exist_ok=True)
|
|
240
|
-
log_file = os.path.join(log_dir, "auto-coder.log")
|
|
241
|
-
|
|
242
|
-
# 配置全局日志
|
|
243
|
-
# 默认情况下,所有日志都写入文件
|
|
244
|
-
# 控制台上默认不输出任何日志,除非显式配置
|
|
245
|
-
global_logger.configure(
|
|
246
|
-
handlers=[
|
|
247
|
-
{
|
|
248
|
-
"sink": log_file,
|
|
249
|
-
"level": "INFO",
|
|
250
|
-
"rotation": "10 MB",
|
|
251
|
-
"retention": "1 week",
|
|
252
|
-
"format": "{time:YYYY-MM-DD HH:mm:ss} | {level} | {name} | {message}",
|
|
253
|
-
},
|
|
254
|
-
{
|
|
255
|
-
"sink": sys.stdout,
|
|
256
|
-
"level": "INFO",
|
|
257
|
-
"format": "{time:YYYY-MM-DD HH:mm:ss} | {name} | {message}",
|
|
258
|
-
# 默认不打印任何日志到控制台
|
|
259
|
-
"filter": lambda record: False
|
|
260
|
-
}
|
|
261
|
-
]
|
|
262
|
-
)
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
def init_singleton_instances():
|
|
266
|
-
# 初始化文件监控系统
|
|
267
|
-
try:
|
|
268
|
-
FileMonitor(project_root).start()
|
|
269
|
-
except Exception as e:
|
|
270
|
-
global_logger.error(f"Failed to start file monitor: {e}")
|
|
271
|
-
global_logger.exception(e)
|
|
272
|
-
|
|
273
|
-
# 初始化规则文件管理器
|
|
274
|
-
from autocoder.common.rulefiles.autocoderrules_utils import get_rules
|
|
275
|
-
get_rules(project_root=project_root)
|
|
276
|
-
|
|
277
|
-
# 初始化忽略文件管理器
|
|
278
|
-
from autocoder.common.ignorefiles.ignore_file_utils import IgnoreFileManager
|
|
279
|
-
_ = IgnoreFileManager(project_root=project_root)
|
|
280
|
-
|
|
281
327
|
|
|
282
|
-
def start():
|
|
283
|
-
if os.environ.get(
|
|
328
|
+
def start():
|
|
329
|
+
if os.environ.get("autocoder_auto_init", "true") in ["true", "True", "True", True]:
|
|
284
330
|
configure_logger()
|
|
285
331
|
init_singleton_instances()
|
|
286
332
|
|
|
@@ -292,7 +338,7 @@ def start():
|
|
|
292
338
|
# name = f"{time_str}-{str(uuid.uuid4())}"
|
|
293
339
|
# conversation_id = conversation_manager.create_new_conversation(name=name,description="")
|
|
294
340
|
# conversation_manager.set_current_conversation(conversation_id)
|
|
295
|
-
|
|
341
|
+
|
|
296
342
|
|
|
297
343
|
def stop():
|
|
298
344
|
try:
|
|
@@ -301,9 +347,11 @@ def stop():
|
|
|
301
347
|
global_logger.error(f"Failed to stop file monitor: {e}")
|
|
302
348
|
global_logger.exception(e)
|
|
303
349
|
|
|
304
|
-
|
|
350
|
+
|
|
351
|
+
def initialize_system(args: InitializeSystemRequest):
|
|
305
352
|
from autocoder.utils.model_provider_selector import ModelProviderSelector
|
|
306
|
-
from autocoder import
|
|
353
|
+
from autocoder.common.llms import LLMManager
|
|
354
|
+
|
|
307
355
|
print(f"\n\033[1;34m{get_message('initializing')}\033[0m")
|
|
308
356
|
|
|
309
357
|
first_time = [False]
|
|
@@ -319,54 +367,42 @@ def initialize_system(args:InitializeSystemRequest):
|
|
|
319
367
|
else:
|
|
320
368
|
print(f" {message}")
|
|
321
369
|
|
|
322
|
-
def init_project():
|
|
323
|
-
if not os.path.exists(".auto-coder") or not os.path.exists("actions"):
|
|
324
|
-
first_time[0] = True
|
|
325
|
-
print_status(get_message("not_initialized"), "warning")
|
|
326
|
-
init_choice = input(
|
|
327
|
-
f" {get_message('init_prompt')}").strip().lower()
|
|
328
|
-
if init_choice == "y":
|
|
329
|
-
try:
|
|
330
|
-
subprocess.run(
|
|
331
|
-
["auto-coder", "init", "--source_dir", "."], check=True
|
|
332
|
-
)
|
|
333
|
-
print_status(get_message("init_success"), "success")
|
|
334
|
-
except subprocess.CalledProcessError:
|
|
335
|
-
print_status(get_message("init_fail"), "error")
|
|
336
|
-
print_status(get_message("init_manual"), "warning")
|
|
337
|
-
exit(1)
|
|
338
|
-
else:
|
|
339
|
-
print_status(get_message("exit_no_init"), "warning")
|
|
340
|
-
exit(1)
|
|
341
|
-
|
|
342
370
|
if not os.path.exists(base_persist_dir):
|
|
343
371
|
os.makedirs(base_persist_dir, exist_ok=True)
|
|
344
|
-
print_status(
|
|
372
|
+
print_status(
|
|
373
|
+
get_message_with_format("created_dir", path=base_persist_dir), "success"
|
|
374
|
+
)
|
|
345
375
|
|
|
346
376
|
if first_time[0]:
|
|
347
|
-
|
|
377
|
+
configure("project_type:*", skip_print=True)
|
|
348
378
|
configure_success[0] = True
|
|
349
379
|
|
|
350
380
|
print_status(get_message("init_complete"), "success")
|
|
351
381
|
|
|
352
|
-
|
|
382
|
+
init_project_if_required(target_dir=project_root, project_type="*")
|
|
353
383
|
|
|
354
384
|
if not args.skip_provider_selection and first_time[0]:
|
|
355
|
-
if args.product_mode == "lite":
|
|
356
|
-
|
|
385
|
+
if args.product_mode == "lite":
|
|
386
|
+
# 如果已经是配置过的项目,就无需再选择
|
|
357
387
|
if first_time[0]:
|
|
358
|
-
|
|
388
|
+
llm_manager = LLMManager()
|
|
389
|
+
if not llm_manager.check_model_exists(
|
|
390
|
+
"v3_chat"
|
|
391
|
+
) or not llm_manager.check_model_exists("r1_chat"):
|
|
359
392
|
model_provider_selector = ModelProviderSelector()
|
|
360
393
|
model_provider_info = model_provider_selector.select_provider()
|
|
361
394
|
if model_provider_info is not None:
|
|
362
|
-
models_json_list = model_provider_selector.to_models_json(
|
|
363
|
-
|
|
395
|
+
models_json_list = model_provider_selector.to_models_json(
|
|
396
|
+
model_provider_info
|
|
397
|
+
)
|
|
398
|
+
llm_manager.add_models(models_json_list)
|
|
364
399
|
|
|
365
400
|
if args.product_mode == "pro":
|
|
366
401
|
# Check if Ray is running
|
|
367
402
|
print_status(get_message("checking_ray"), "")
|
|
368
403
|
ray_status = subprocess.run(
|
|
369
|
-
["ray", "status"], capture_output=True, text=True
|
|
404
|
+
["ray", "status"], capture_output=True, text=True
|
|
405
|
+
)
|
|
370
406
|
if ray_status.returncode != 0:
|
|
371
407
|
print_status(get_message("ray_not_running"), "warning")
|
|
372
408
|
try:
|
|
@@ -389,7 +425,6 @@ def initialize_system(args:InitializeSystemRequest):
|
|
|
389
425
|
)
|
|
390
426
|
if result.returncode == 0:
|
|
391
427
|
print_status(get_message("model_available"), "success")
|
|
392
|
-
init_project()
|
|
393
428
|
print_status(get_message("init_complete_final"), "success")
|
|
394
429
|
return
|
|
395
430
|
except subprocess.TimeoutExpired:
|
|
@@ -428,7 +463,6 @@ def initialize_system(args:InitializeSystemRequest):
|
|
|
428
463
|
print_status(get_message("deploy_fail"), "error")
|
|
429
464
|
return
|
|
430
465
|
|
|
431
|
-
|
|
432
466
|
deploy_cmd = [
|
|
433
467
|
"byzerllm",
|
|
434
468
|
"deploy",
|
|
@@ -471,14 +505,18 @@ def initialize_system(args:InitializeSystemRequest):
|
|
|
471
505
|
print_status(get_message("manual_start"), "warning")
|
|
472
506
|
print_status("easy-byzerllm chat v3_chat 你好", "")
|
|
473
507
|
|
|
474
|
-
print_status(get_message("init_complete_final"), "success")
|
|
508
|
+
print_status(get_message("init_complete_final"), "success")
|
|
475
509
|
configure_success[0] = True
|
|
476
510
|
|
|
477
511
|
if first_time[0] and args.product_mode == "pro" and configure_success[0]:
|
|
478
|
-
configure(f"model:v3_chat", skip_print=True)
|
|
512
|
+
configure(f"model:v3_chat", skip_print=True)
|
|
479
513
|
|
|
480
|
-
if
|
|
481
|
-
|
|
514
|
+
if (
|
|
515
|
+
first_time[0]
|
|
516
|
+
and args.product_mode == "lite"
|
|
517
|
+
and LLMManager().check_model_exists("v3_chat")
|
|
518
|
+
):
|
|
519
|
+
configure(f"model:v3_chat", skip_print=True)
|
|
482
520
|
|
|
483
521
|
|
|
484
522
|
def convert_yaml_config_to_str(yaml_config):
|
|
@@ -491,92 +529,44 @@ def convert_yaml_config_to_str(yaml_config):
|
|
|
491
529
|
return yaml_content
|
|
492
530
|
|
|
493
531
|
|
|
494
|
-
def get_all_file_names_in_project() -> List[str]:
|
|
495
|
-
|
|
496
|
-
file_names = []
|
|
497
|
-
final_exclude_dirs = defaut_exclude_dirs + memory.get("exclude_dirs", [])
|
|
498
|
-
for root, dirs, files in os.walk(project_root, followlinks=True):
|
|
499
|
-
dirs[:] = [d for d in dirs if d not in final_exclude_dirs]
|
|
500
|
-
file_names.extend(files)
|
|
501
|
-
return file_names
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
def get_all_file_in_project() -> List[str]:
|
|
505
|
-
|
|
506
|
-
file_names = []
|
|
507
|
-
final_exclude_dirs = defaut_exclude_dirs + memory.get("exclude_dirs", [])
|
|
508
|
-
for root, dirs, files in os.walk(project_root, followlinks=True):
|
|
509
|
-
dirs[:] = [d for d in dirs if d not in final_exclude_dirs]
|
|
510
|
-
for file in files:
|
|
511
|
-
file_names.append(os.path.join(root, file))
|
|
512
|
-
return file_names
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
def get_all_file_in_project_with_dot() -> List[str]:
|
|
516
|
-
file_names = []
|
|
517
|
-
final_exclude_dirs = defaut_exclude_dirs + memory.get("exclude_dirs", [])
|
|
518
|
-
for root, dirs, files in os.walk(project_root, followlinks=True):
|
|
519
|
-
dirs[:] = [d for d in dirs if d not in final_exclude_dirs]
|
|
520
|
-
for file in files:
|
|
521
|
-
file_names.append(os.path.join(
|
|
522
|
-
root, file).replace(project_root, "."))
|
|
523
|
-
return file_names
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
def get_all_dir_names_in_project() -> List[str]:
|
|
527
|
-
dir_names = []
|
|
528
|
-
final_exclude_dirs = defaut_exclude_dirs + memory.get("exclude_dirs", [])
|
|
529
|
-
for root, dirs, files in os.walk(project_root, followlinks=True):
|
|
530
|
-
dirs[:] = [d for d in dirs if d not in final_exclude_dirs]
|
|
531
|
-
for dir in dirs:
|
|
532
|
-
dir_names.append(dir)
|
|
533
|
-
return dir_names
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
def find_files_in_project(patterns: List[str]) -> List[str]:
|
|
537
|
-
matched_files = []
|
|
538
|
-
final_exclude_dirs = defaut_exclude_dirs + memory.get("exclude_dirs", [])
|
|
539
|
-
|
|
540
|
-
for pattern in patterns:
|
|
541
|
-
if "*" in pattern or "?" in pattern:
|
|
542
|
-
for file_path in glob.glob(pattern, recursive=True):
|
|
543
|
-
if os.path.isfile(file_path):
|
|
544
|
-
abs_path = os.path.abspath(file_path)
|
|
545
|
-
if not any(
|
|
546
|
-
exclude_dir in abs_path.split(os.sep)
|
|
547
|
-
for exclude_dir in final_exclude_dirs
|
|
548
|
-
):
|
|
549
|
-
matched_files.append(abs_path)
|
|
550
|
-
else:
|
|
551
|
-
is_added = False
|
|
552
|
-
# add files belongs to project
|
|
553
|
-
for root, dirs, files in os.walk(project_root, followlinks=True):
|
|
554
|
-
dirs[:] = [d for d in dirs if d not in final_exclude_dirs]
|
|
555
|
-
if pattern in files:
|
|
556
|
-
matched_files.append(os.path.join(root, pattern))
|
|
557
|
-
is_added = True
|
|
558
|
-
else:
|
|
559
|
-
for file in files:
|
|
560
|
-
_pattern = os.path.abspath(pattern)
|
|
561
|
-
if _pattern in os.path.join(root, file):
|
|
562
|
-
matched_files.append(os.path.join(root, file))
|
|
563
|
-
is_added = True
|
|
564
|
-
# add files not belongs to project
|
|
565
|
-
if not is_added:
|
|
566
|
-
matched_files.append(pattern)
|
|
567
|
-
|
|
568
|
-
return list(set(matched_files))
|
|
569
|
-
|
|
570
|
-
|
|
571
532
|
def convert_config_value(key, value):
|
|
533
|
+
# 定义需要使用 token 解析的字段
|
|
534
|
+
token_fields = {
|
|
535
|
+
"conversation_prune_safe_zone_tokens",
|
|
536
|
+
"context_prune_safe_zone_tokens",
|
|
537
|
+
"context_prune_sliding_window_size",
|
|
538
|
+
"context_prune_sliding_window_overlap",
|
|
539
|
+
"rag_params_max_tokens",
|
|
540
|
+
"rag_context_window_limit",
|
|
541
|
+
"rag_duckdb_vector_dim",
|
|
542
|
+
"rag_duckdb_query_top_k",
|
|
543
|
+
"rag_emb_dim",
|
|
544
|
+
"rag_emb_text_size",
|
|
545
|
+
"hybrid_index_max_output_tokens",
|
|
546
|
+
"data_cells_max_num",
|
|
547
|
+
}
|
|
548
|
+
|
|
572
549
|
field_info = AutoCoderArgs.model_fields.get(key)
|
|
573
550
|
if field_info:
|
|
551
|
+
# 对于需要 token 解析的字段,使用 AutoCoderArgsParser
|
|
552
|
+
if key in token_fields:
|
|
553
|
+
try:
|
|
554
|
+
parser = AutoCoderArgsParser()
|
|
555
|
+
return parser.parse_token_field(key, value)
|
|
556
|
+
except Exception as e:
|
|
557
|
+
print(
|
|
558
|
+
f"Warning: Failed to parse token field '{key}' with value '{value}': {e}"
|
|
559
|
+
)
|
|
560
|
+
# 如果解析失败,fallback 到原有逻辑
|
|
561
|
+
pass
|
|
562
|
+
|
|
563
|
+
# 原有的类型转换逻辑
|
|
574
564
|
if isinstance(value, str) and value.lower() in ["true", "false"]:
|
|
575
565
|
return value.lower() == "true"
|
|
576
|
-
elif "int" in str(field_info.annotation):
|
|
577
|
-
return int(value)
|
|
578
566
|
elif "float" in str(field_info.annotation):
|
|
579
567
|
return float(value)
|
|
568
|
+
elif "int" in str(field_info.annotation):
|
|
569
|
+
return int(value)
|
|
580
570
|
else:
|
|
581
571
|
return value
|
|
582
572
|
else:
|
|
@@ -594,14 +584,14 @@ def redirect_stdout():
|
|
|
594
584
|
sys.stdout = original_stdout
|
|
595
585
|
|
|
596
586
|
|
|
597
|
-
def configure(conf: str, skip_print=
|
|
587
|
+
def configure(conf: str, skip_print=True):
|
|
598
588
|
printer = Printer()
|
|
589
|
+
memory_manager = get_memory_manager()
|
|
599
590
|
parts = conf.split(None, 1)
|
|
600
591
|
if len(parts) == 2 and parts[0] in ["/drop", "/unset", "/remove"]:
|
|
601
592
|
key = parts[1].strip()
|
|
602
|
-
if key
|
|
603
|
-
|
|
604
|
-
save_memory()
|
|
593
|
+
if memory_manager.has_config(key):
|
|
594
|
+
memory_manager.delete_config(key)
|
|
605
595
|
printer.print_in_terminal("config_delete_success", style="green", key=key)
|
|
606
596
|
else:
|
|
607
597
|
printer.print_in_terminal("config_not_found", style="yellow", key=key)
|
|
@@ -616,109 +606,75 @@ def configure(conf: str, skip_print=False):
|
|
|
616
606
|
if not value:
|
|
617
607
|
printer.print_in_terminal("config_value_empty", style="red")
|
|
618
608
|
return
|
|
619
|
-
product_mode =
|
|
609
|
+
product_mode = memory_manager.get_config("product_mode", None)
|
|
620
610
|
if product_mode:
|
|
621
|
-
ConfigValidator.validate(key, value, product_mode)
|
|
622
|
-
|
|
623
|
-
save_memory()
|
|
611
|
+
ConfigValidator.validate(key, value, product_mode)
|
|
612
|
+
memory_manager.set_config(key, value)
|
|
624
613
|
if not skip_print:
|
|
625
|
-
printer.print_in_terminal(
|
|
614
|
+
printer.print_in_terminal(
|
|
615
|
+
"config_set_success", style="green", key=key, value=value
|
|
616
|
+
)
|
|
617
|
+
|
|
626
618
|
|
|
627
619
|
# word_completer = WordCompleter(commands)
|
|
628
620
|
|
|
629
621
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
622
|
+
# Memory management functions are now imported from core_config module
|
|
623
|
+
# Helper functions to access memory without global variables
|
|
624
|
+
def get_current_memory():
|
|
625
|
+
"""Get current memory as dictionary for backward compatibility"""
|
|
626
|
+
return get_memory()
|
|
633
627
|
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
628
|
+
|
|
629
|
+
def get_current_files():
|
|
630
|
+
"""Get current files list"""
|
|
631
|
+
memory_manager = get_memory_manager()
|
|
632
|
+
return memory_manager.get_current_files()
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
def set_current_files(files):
|
|
636
|
+
"""Set current files list"""
|
|
637
|
+
memory_manager = get_memory_manager()
|
|
638
|
+
memory_manager.set_current_files(files)
|
|
639
|
+
|
|
640
|
+
|
|
641
|
+
def get_file_groups():
|
|
642
|
+
"""Get file groups"""
|
|
643
|
+
memory_manager = get_memory_manager()
|
|
644
|
+
return memory_manager.get_file_groups()
|
|
645
|
+
|
|
646
|
+
|
|
647
|
+
def get_exclude_dirs():
|
|
648
|
+
"""Get exclude directories"""
|
|
649
|
+
memory_manager = get_memory_manager()
|
|
650
|
+
return memory_manager.get_exclude_dirs()
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
# 使用 project_scanner 模块创建兼容函数(供其他地方使用)
|
|
654
|
+
scanner_funcs = create_scanner_functions(
|
|
655
|
+
project_root=project_root,
|
|
656
|
+
default_exclude_dirs=defaut_exclude_dirs,
|
|
657
|
+
get_extra_exclude_dirs_func=get_exclude_dirs,
|
|
658
|
+
)
|
|
659
|
+
|
|
660
|
+
# 导出兼容函数
|
|
661
|
+
get_all_file_names_in_project = scanner_funcs["get_all_file_names_in_project"]
|
|
662
|
+
get_all_file_in_project = scanner_funcs["get_all_file_in_project"]
|
|
663
|
+
get_all_file_in_project_with_dot = scanner_funcs["get_all_file_in_project_with_dot"]
|
|
664
|
+
get_all_dir_names_in_project = scanner_funcs["get_all_dir_names_in_project"]
|
|
665
|
+
find_files_in_project = scanner_funcs["find_files_in_project"]
|
|
666
|
+
get_symbol_list = scanner_funcs["get_symbol_list"]
|
|
667
|
+
|
|
668
|
+
# 直接创建 CommandCompleterV2,它内部会使用 project_scanner
|
|
669
|
+
completer = CommandCompleterV2(
|
|
670
|
+
commands,
|
|
671
|
+
memory_model=CCMemoryModel(
|
|
672
|
+
get_memory_func=get_memory, save_memory_func=save_memory
|
|
673
|
+
),
|
|
674
|
+
project_root=project_root,
|
|
675
|
+
)
|
|
669
676
|
|
|
670
677
|
|
|
671
|
-
def save_memory():
|
|
672
|
-
memory_path = os.path.join(base_persist_dir, "memory.json")
|
|
673
|
-
lock_path = memory_path + ".lock"
|
|
674
|
-
|
|
675
|
-
with FileLock(lock_path, timeout=30):
|
|
676
|
-
with open(memory_path, "w", encoding="utf-8") as f:
|
|
677
|
-
json.dump(memory, f, indent=2, ensure_ascii=False)
|
|
678
|
-
|
|
679
|
-
load_memory()
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
def save_memory_with_new_memory(new_memory):
|
|
683
|
-
memory_path = os.path.join(base_persist_dir, "memory.json")
|
|
684
|
-
lock_path = memory_path + ".lock"
|
|
685
|
-
|
|
686
|
-
with FileLock(lock_path, timeout=30):
|
|
687
|
-
with open(memory_path, "w", encoding="utf-8") as f:
|
|
688
|
-
json.dump(new_memory, f, indent=2, ensure_ascii=False)
|
|
689
|
-
load_memory()
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
def load_memory():
|
|
693
|
-
global memory
|
|
694
|
-
memory_path = os.path.join(base_persist_dir, "memory.json")
|
|
695
|
-
lock_path = memory_path + ".lock"
|
|
696
|
-
|
|
697
|
-
if os.path.exists(memory_path):
|
|
698
|
-
with FileLock(lock_path, timeout=30):
|
|
699
|
-
with open(memory_path, "r", encoding="utf-8") as f:
|
|
700
|
-
_memory = json.load(f)
|
|
701
|
-
# clear memory
|
|
702
|
-
memory.clear()
|
|
703
|
-
memory.update(_memory)
|
|
704
|
-
return memory
|
|
705
|
-
|
|
706
|
-
def get_memory():
|
|
707
|
-
return load_memory()
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
from autocoder.common.command_completer_v2 import CommandCompleterV2
|
|
711
|
-
completer = CommandCompleterV2(commands,
|
|
712
|
-
file_system_model=CCFileSystemModel(project_root=project_root,
|
|
713
|
-
defaut_exclude_dirs=defaut_exclude_dirs,
|
|
714
|
-
get_all_file_names_in_project=get_all_file_names_in_project,
|
|
715
|
-
get_all_file_in_project=get_all_file_in_project,
|
|
716
|
-
get_all_dir_names_in_project=get_all_dir_names_in_project,
|
|
717
|
-
get_all_file_in_project_with_dot=get_all_file_in_project_with_dot,
|
|
718
|
-
get_symbol_list=get_symbol_list
|
|
719
|
-
),
|
|
720
|
-
memory_model=CCMemoryModel(get_memory_func=get_memory,
|
|
721
|
-
save_memory_func=save_memory))
|
|
722
678
|
def revert():
|
|
723
679
|
result_manager = ResultManager()
|
|
724
680
|
last_yaml_file = get_last_yaml_file("actions")
|
|
@@ -728,57 +684,36 @@ def revert():
|
|
|
728
684
|
with redirect_stdout() as output:
|
|
729
685
|
auto_coder_main(["revert", "--file", file_path])
|
|
730
686
|
s = output.getvalue()
|
|
731
|
-
|
|
687
|
+
|
|
732
688
|
console = Console()
|
|
733
689
|
panel = Panel(
|
|
734
690
|
Markdown(s),
|
|
735
691
|
title="Revert Result",
|
|
736
692
|
border_style="green" if "Successfully reverted changes" in s else "red",
|
|
737
693
|
padding=(1, 2),
|
|
738
|
-
expand=False
|
|
694
|
+
expand=False,
|
|
739
695
|
)
|
|
740
696
|
console.print(panel)
|
|
741
|
-
|
|
697
|
+
|
|
742
698
|
if "Successfully reverted changes" in s:
|
|
743
|
-
result_manager.append(
|
|
744
|
-
|
|
699
|
+
result_manager.append(
|
|
700
|
+
content=s, meta={"action": "revert", "success": False, "input": {}}
|
|
701
|
+
)
|
|
745
702
|
else:
|
|
746
|
-
result_manager.append(
|
|
747
|
-
|
|
703
|
+
result_manager.append(
|
|
704
|
+
content=s, meta={"action": "revert", "success": False, "input": {}}
|
|
705
|
+
)
|
|
748
706
|
else:
|
|
749
|
-
result_manager.append(
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
def add_files(args: List[str]):
|
|
754
|
-
|
|
755
|
-
result_manager = ResultManager()
|
|
756
|
-
if "groups" not in memory["current_files"]:
|
|
757
|
-
memory["current_files"]["groups"] = {}
|
|
758
|
-
if "groups_info" not in memory["current_files"]:
|
|
759
|
-
memory["current_files"]["groups_info"] = {}
|
|
760
|
-
if "current_groups" not in memory["current_files"]:
|
|
761
|
-
memory["current_files"]["current_groups"] = []
|
|
762
|
-
groups = memory["current_files"]["groups"]
|
|
763
|
-
groups_info = memory["current_files"]["groups_info"]
|
|
764
|
-
|
|
765
|
-
console = Console()
|
|
766
|
-
printer = Printer()
|
|
767
|
-
|
|
768
|
-
if not args:
|
|
769
|
-
printer.print_in_terminal("add_files_no_args", style="red")
|
|
770
|
-
result_manager.append(content=printer.get_message_from_key("add_files_no_args"),
|
|
771
|
-
meta={"action": "add_files","success":False, "input":{ "args": args}})
|
|
772
|
-
return
|
|
773
|
-
|
|
774
|
-
if args[0] == "/refresh":
|
|
775
|
-
completer.refresh_files()
|
|
707
|
+
result_manager.append(
|
|
708
|
+
content="No previous chat action found to revert.",
|
|
709
|
+
meta={"action": "revert", "success": False, "input": {}},
|
|
710
|
+
)
|
|
776
711
|
|
|
777
712
|
|
|
778
713
|
def _handle_post_commit_and_pr(post_commit: bool, pr: bool, query: str, args, llm):
|
|
779
714
|
"""
|
|
780
715
|
处理 post_commit 和 PR 功能
|
|
781
|
-
|
|
716
|
+
|
|
782
717
|
Args:
|
|
783
718
|
post_commit: 是否执行 post_commit
|
|
784
719
|
pr: 是否创建 PR
|
|
@@ -787,13 +722,11 @@ def _handle_post_commit_and_pr(post_commit: bool, pr: bool, query: str, args, ll
|
|
|
787
722
|
llm: LLM 实例
|
|
788
723
|
"""
|
|
789
724
|
printer = Printer()
|
|
790
|
-
console = Console()
|
|
791
|
-
|
|
792
725
|
try:
|
|
793
726
|
if post_commit:
|
|
794
727
|
# 执行 post_commit 操作
|
|
795
728
|
printer.print_in_terminal("post_commit_executing", style="blue")
|
|
796
|
-
|
|
729
|
+
|
|
797
730
|
# 检查是否有未提交的更改
|
|
798
731
|
uncommitted_changes = git_utils.get_uncommitted_changes(".")
|
|
799
732
|
if uncommitted_changes:
|
|
@@ -801,102 +734,120 @@ def _handle_post_commit_and_pr(post_commit: bool, pr: bool, query: str, args, ll
|
|
|
801
734
|
commit_message = git_utils.generate_commit_message.with_llm(llm).run(
|
|
802
735
|
uncommitted_changes
|
|
803
736
|
)
|
|
804
|
-
|
|
737
|
+
|
|
805
738
|
# 执行提交
|
|
806
739
|
commit_result = git_utils.commit_changes(".", commit_message)
|
|
807
740
|
git_utils.print_commit_info(commit_result=commit_result)
|
|
808
|
-
printer.print_in_terminal(
|
|
809
|
-
|
|
741
|
+
printer.print_in_terminal(
|
|
742
|
+
"post_commit_success", style="green", message=commit_message
|
|
743
|
+
)
|
|
744
|
+
|
|
810
745
|
# 如果需要创建 PR,则继续处理
|
|
811
746
|
if pr:
|
|
812
747
|
_create_pull_request(commit_result, query, llm)
|
|
813
748
|
else:
|
|
814
749
|
printer.print_in_terminal("post_commit_no_changes", style="yellow")
|
|
815
|
-
|
|
750
|
+
|
|
816
751
|
elif pr:
|
|
817
752
|
# 只创建 PR,不执行 post_commit
|
|
818
753
|
# 获取最后一个 commit
|
|
819
754
|
try:
|
|
820
755
|
repo = git.Repo(".")
|
|
821
756
|
last_commit = repo.head.commit
|
|
822
|
-
|
|
757
|
+
|
|
823
758
|
# 创建一个模拟的 commit_result 对象
|
|
824
759
|
class MockCommitResult:
|
|
825
760
|
def __init__(self, commit):
|
|
826
761
|
self.commit_hash = commit.hexsha
|
|
827
762
|
self.commit_message = commit.message.strip()
|
|
828
763
|
self.changed_files = []
|
|
829
|
-
|
|
764
|
+
|
|
830
765
|
mock_commit_result = MockCommitResult(last_commit)
|
|
831
766
|
_create_pull_request(mock_commit_result, query, llm)
|
|
832
|
-
|
|
767
|
+
|
|
833
768
|
except Exception as e:
|
|
834
|
-
printer.print_in_terminal(
|
|
835
|
-
|
|
769
|
+
printer.print_in_terminal(
|
|
770
|
+
"pr_get_last_commit_failed", style="red", error=str(e)
|
|
771
|
+
)
|
|
772
|
+
|
|
836
773
|
except Exception as e:
|
|
837
774
|
printer.print_in_terminal("post_commit_pr_failed", style="red", error=str(e))
|
|
838
775
|
|
|
839
|
-
|
|
776
|
+
|
|
777
|
+
def init_project_if_required(target_dir: str, project_type: str):
|
|
840
778
|
"""
|
|
841
779
|
如果项目没有初始化,则自动初始化项目
|
|
842
|
-
|
|
780
|
+
|
|
843
781
|
Args:
|
|
844
782
|
target_dir: 目标目录路径
|
|
845
|
-
"""
|
|
846
|
-
|
|
783
|
+
"""
|
|
784
|
+
|
|
847
785
|
# 确保目标目录是绝对路径
|
|
848
786
|
if not os.path.isabs(target_dir):
|
|
849
787
|
target_dir = os.path.abspath(target_dir)
|
|
850
|
-
|
|
788
|
+
|
|
851
789
|
actions_dir = os.path.join(target_dir, "actions")
|
|
852
790
|
auto_coder_dir = os.path.join(target_dir, ".auto-coder")
|
|
853
|
-
|
|
791
|
+
|
|
854
792
|
# 检查是否已经初始化
|
|
855
793
|
if os.path.exists(actions_dir) and os.path.exists(auto_coder_dir):
|
|
856
794
|
return # 已经初始化,无需再次初始化
|
|
857
|
-
|
|
795
|
+
|
|
858
796
|
printer = Printer()
|
|
859
|
-
|
|
860
|
-
try:
|
|
797
|
+
|
|
798
|
+
try:
|
|
861
799
|
# 创建必要的目录
|
|
862
800
|
os.makedirs(actions_dir, exist_ok=True)
|
|
863
801
|
os.makedirs(auto_coder_dir, exist_ok=True)
|
|
864
|
-
|
|
802
|
+
|
|
865
803
|
# 导入并使用 create_actions 创建默认的 action 文件
|
|
866
804
|
from autocoder.common.command_templates import create_actions
|
|
867
|
-
|
|
805
|
+
|
|
868
806
|
create_actions(
|
|
869
807
|
source_dir=target_dir,
|
|
870
|
-
params={
|
|
871
|
-
"project_type": project_type,
|
|
872
|
-
"source_dir": target_dir
|
|
873
|
-
},
|
|
808
|
+
params={"project_type": project_type, "source_dir": target_dir},
|
|
874
809
|
)
|
|
875
|
-
|
|
810
|
+
|
|
876
811
|
# 初始化 git 仓库
|
|
877
812
|
try:
|
|
878
813
|
git_utils.init(target_dir)
|
|
879
814
|
except Exception as e:
|
|
880
815
|
global_logger.warning(f"Failed to initialize git repository: {e}")
|
|
881
|
-
|
|
816
|
+
|
|
882
817
|
# 创建或更新 .gitignore 文件
|
|
883
818
|
gitignore_path = os.path.join(target_dir, ".gitignore")
|
|
884
|
-
gitignore_entries = [
|
|
885
|
-
|
|
819
|
+
gitignore_entries = [
|
|
820
|
+
".auto-coder/",
|
|
821
|
+
"/actions/",
|
|
822
|
+
"/output.txt",
|
|
823
|
+
".autocoderrules",
|
|
824
|
+
".autocodertools",
|
|
825
|
+
".autocodercommands",
|
|
826
|
+
".autocoderagents",
|
|
827
|
+
".autocoderlinters",
|
|
828
|
+
]
|
|
829
|
+
|
|
886
830
|
try:
|
|
887
|
-
#
|
|
888
|
-
|
|
831
|
+
# 读取现有的 .gitignore 内容
|
|
832
|
+
existing_entries = set()
|
|
889
833
|
if os.path.exists(gitignore_path):
|
|
890
834
|
with open(gitignore_path, "r", encoding="utf-8") as f:
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
835
|
+
# 将现有内容按行分割并去除空白字符,转换为集合以便快速查找
|
|
836
|
+
existing_entries = {line.strip() for line in f if line.strip()}
|
|
837
|
+
|
|
838
|
+
# 筛选出需要添加的新条目
|
|
839
|
+
new_entries = [
|
|
840
|
+
entry for entry in gitignore_entries if entry not in existing_entries
|
|
841
|
+
]
|
|
842
|
+
|
|
843
|
+
# 如果有新条目需要添加,则写入文件
|
|
844
|
+
if new_entries:
|
|
845
|
+
with open(gitignore_path, "a", encoding="utf-8") as f:
|
|
846
|
+
for entry in new_entries:
|
|
847
|
+
f.write(f"\n{entry}")
|
|
897
848
|
except Exception as e:
|
|
898
849
|
global_logger.warning(f"Failed to update .gitignore: {e}")
|
|
899
|
-
|
|
850
|
+
|
|
900
851
|
# 创建 .autocoderignore 文件
|
|
901
852
|
try:
|
|
902
853
|
autocoderignore_path = os.path.join(target_dir, ".autocoderignore")
|
|
@@ -907,9 +858,11 @@ def init_project_if_required(target_dir: str,project_type:str):
|
|
|
907
858
|
except Exception as e:
|
|
908
859
|
global_logger.warning(f"Failed to create .autocoderignore: {e}")
|
|
909
860
|
|
|
910
|
-
configure(f"project_type:{project_type}")
|
|
911
|
-
global_logger.info(
|
|
912
|
-
|
|
861
|
+
configure(f"project_type:{project_type}", skip_print=True)
|
|
862
|
+
global_logger.info(
|
|
863
|
+
f"Successfully initialized auto-coder project in {target_dir}"
|
|
864
|
+
)
|
|
865
|
+
|
|
913
866
|
except Exception as e:
|
|
914
867
|
global_logger.error(f"Failed to initialize project in {target_dir}: {e}")
|
|
915
868
|
printer.print_in_terminal("init_project_error", style="red", error=str(e))
|
|
@@ -918,7 +871,7 @@ def init_project_if_required(target_dir: str,project_type:str):
|
|
|
918
871
|
def _create_pull_request(commit_result, original_query: str, llm):
|
|
919
872
|
"""
|
|
920
873
|
创建 Pull Request
|
|
921
|
-
|
|
874
|
+
|
|
922
875
|
Args:
|
|
923
876
|
commit_result: 提交结果对象
|
|
924
877
|
original_query: 原始查询
|
|
@@ -926,76 +879,92 @@ def _create_pull_request(commit_result, original_query: str, llm):
|
|
|
926
879
|
"""
|
|
927
880
|
printer = Printer()
|
|
928
881
|
console = Console()
|
|
929
|
-
|
|
882
|
+
|
|
930
883
|
try:
|
|
931
884
|
# 检查是否安装了 gh CLI
|
|
932
885
|
gh_check = subprocess.run(["gh", "--version"], capture_output=True, text=True)
|
|
933
886
|
if gh_check.returncode != 0:
|
|
934
887
|
printer.print_in_terminal("pr_gh_not_installed", style="red")
|
|
935
888
|
return
|
|
936
|
-
|
|
889
|
+
|
|
937
890
|
# 检查是否已经登录 GitHub
|
|
938
|
-
auth_check = subprocess.run(
|
|
891
|
+
auth_check = subprocess.run(
|
|
892
|
+
["gh", "auth", "status"], capture_output=True, text=True
|
|
893
|
+
)
|
|
939
894
|
if auth_check.returncode != 0:
|
|
940
895
|
printer.print_in_terminal("pr_gh_not_authenticated", style="red")
|
|
941
896
|
return
|
|
942
|
-
|
|
897
|
+
|
|
943
898
|
# 获取当前分支名
|
|
944
899
|
repo = git.Repo(".")
|
|
945
900
|
current_branch = repo.active_branch.name
|
|
946
|
-
|
|
901
|
+
|
|
947
902
|
# 如果在 main/master 分支,创建新分支
|
|
948
903
|
if current_branch in ["main", "master"]:
|
|
949
904
|
# 生成新分支名
|
|
950
905
|
import re
|
|
951
|
-
|
|
906
|
+
|
|
907
|
+
branch_name = re.sub(r"[^a-zA-Z0-9\-_]", "-", original_query.lower())
|
|
952
908
|
branch_name = f"auto-coder-{branch_name[:30]}-{int(time.time())}"
|
|
953
|
-
|
|
909
|
+
|
|
954
910
|
# 创建并切换到新分支
|
|
955
911
|
new_branch = repo.create_head(branch_name)
|
|
956
912
|
new_branch.checkout()
|
|
957
913
|
current_branch = branch_name
|
|
958
|
-
|
|
959
|
-
printer.print_in_terminal(
|
|
960
|
-
|
|
914
|
+
|
|
915
|
+
printer.print_in_terminal(
|
|
916
|
+
"pr_created_branch", style="blue", branch=branch_name
|
|
917
|
+
)
|
|
918
|
+
|
|
961
919
|
# 推送当前分支到远程
|
|
962
920
|
try:
|
|
963
921
|
origin = repo.remotes.origin
|
|
964
922
|
origin.push(current_branch)
|
|
965
|
-
printer.print_in_terminal(
|
|
923
|
+
printer.print_in_terminal(
|
|
924
|
+
"pr_pushed_branch", style="blue", branch=current_branch
|
|
925
|
+
)
|
|
966
926
|
except Exception as e:
|
|
967
927
|
printer.print_in_terminal("pr_push_failed", style="red", error=str(e))
|
|
968
928
|
return
|
|
969
|
-
|
|
929
|
+
|
|
970
930
|
# 生成 PR 标题和描述
|
|
971
931
|
pr_title, pr_body = _generate_pr_content(commit_result, original_query, llm)
|
|
972
|
-
|
|
932
|
+
|
|
973
933
|
# 创建 PR
|
|
974
934
|
pr_cmd = [
|
|
975
|
-
"gh",
|
|
976
|
-
"
|
|
977
|
-
"
|
|
978
|
-
"--
|
|
935
|
+
"gh",
|
|
936
|
+
"pr",
|
|
937
|
+
"create",
|
|
938
|
+
"--title",
|
|
939
|
+
pr_title,
|
|
940
|
+
"--body",
|
|
941
|
+
pr_body,
|
|
942
|
+
"--head",
|
|
943
|
+
current_branch,
|
|
979
944
|
]
|
|
980
|
-
|
|
945
|
+
|
|
981
946
|
pr_result = subprocess.run(pr_cmd, capture_output=True, text=True)
|
|
982
|
-
|
|
947
|
+
|
|
983
948
|
if pr_result.returncode == 0:
|
|
984
949
|
pr_url = pr_result.stdout.strip()
|
|
985
950
|
printer.print_in_terminal("pr_created_success", style="green", url=pr_url)
|
|
986
|
-
|
|
951
|
+
|
|
987
952
|
# 显示 PR 信息
|
|
988
|
-
console.print(
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
953
|
+
console.print(
|
|
954
|
+
Panel(
|
|
955
|
+
f"[bold green]Pull Request Created Successfully![/bold green]\n\n"
|
|
956
|
+
f"[bold]Title:[/bold] {pr_title}\n"
|
|
957
|
+
f"[bold]URL:[/bold] {pr_url}\n"
|
|
958
|
+
f"[bold]Branch:[/bold] {current_branch}",
|
|
959
|
+
title="🎉 Pull Request",
|
|
960
|
+
border_style="green",
|
|
961
|
+
)
|
|
962
|
+
)
|
|
996
963
|
else:
|
|
997
|
-
printer.print_in_terminal(
|
|
998
|
-
|
|
964
|
+
printer.print_in_terminal(
|
|
965
|
+
"pr_creation_failed", style="red", error=pr_result.stderr
|
|
966
|
+
)
|
|
967
|
+
|
|
999
968
|
except Exception as e:
|
|
1000
969
|
printer.print_in_terminal("pr_creation_error", style="red", error=str(e))
|
|
1001
970
|
|
|
@@ -1004,22 +973,22 @@ def _create_pull_request(commit_result, original_query: str, llm):
|
|
|
1004
973
|
def _generate_pr_content(commit_result, original_query: str, llm) -> tuple:
|
|
1005
974
|
"""
|
|
1006
975
|
生成 PR 标题和描述
|
|
1007
|
-
|
|
976
|
+
|
|
1008
977
|
根据提交信息和原始查询生成合适的 PR 标题和描述。
|
|
1009
|
-
|
|
978
|
+
|
|
1010
979
|
Args:
|
|
1011
980
|
commit_result: 提交结果,包含 commit_message 和 changed_files
|
|
1012
981
|
original_query: 用户的原始查询请求
|
|
1013
|
-
|
|
982
|
+
|
|
1014
983
|
Returns:
|
|
1015
984
|
tuple: (pr_title, pr_body) PR标题和描述内容
|
|
1016
|
-
|
|
985
|
+
|
|
1017
986
|
请生成简洁明了的 PR 标题(不超过72字符)和详细的描述内容。
|
|
1018
987
|
标题应该概括主要变更,描述应该包含:
|
|
1019
988
|
1. 变更的背景和目的
|
|
1020
989
|
2. 主要修改内容
|
|
1021
990
|
3. 影响的文件(如果有的话)
|
|
1022
|
-
|
|
991
|
+
|
|
1023
992
|
提交信息:{{ commit_result.commit_message }}
|
|
1024
993
|
原始需求:{{ original_query }}
|
|
1025
994
|
{% if commit_result.changed_files %}
|
|
@@ -1029,7 +998,7 @@ def _generate_pr_content(commit_result, original_query: str, llm) -> tuple:
|
|
|
1029
998
|
{% endfor %}
|
|
1030
999
|
{% endif %}
|
|
1031
1000
|
"""
|
|
1032
|
-
|
|
1001
|
+
|
|
1033
1002
|
# 这个函数会被 byzerllm 装饰器处理,返回 LLM 生成的内容
|
|
1034
1003
|
# 实际实现会在运行时由装饰器处理
|
|
1035
1004
|
pass
|
|
@@ -1057,14 +1026,14 @@ def _generate_pr_content(commit_result, original_query: str, llm):
|
|
|
1057
1026
|
TITLE: [标题内容]
|
|
1058
1027
|
BODY: [描述内容]
|
|
1059
1028
|
"""
|
|
1060
|
-
|
|
1029
|
+
|
|
1061
1030
|
response = llm.chat([{"role": "user", "content": prompt}])
|
|
1062
|
-
|
|
1031
|
+
|
|
1063
1032
|
# 解析响应
|
|
1064
|
-
lines = response.split(
|
|
1033
|
+
lines = response.split("\n")
|
|
1065
1034
|
title = ""
|
|
1066
1035
|
body = ""
|
|
1067
|
-
|
|
1036
|
+
|
|
1068
1037
|
for line in lines:
|
|
1069
1038
|
if line.startswith("TITLE:"):
|
|
1070
1039
|
title = line.replace("TITLE:", "").strip()
|
|
@@ -1072,15 +1041,15 @@ BODY: [描述内容]
|
|
|
1072
1041
|
body = line.replace("BODY:", "").strip()
|
|
1073
1042
|
elif body: # 如果已经开始收集 body,继续添加后续行
|
|
1074
1043
|
body += "\n" + line
|
|
1075
|
-
|
|
1044
|
+
|
|
1076
1045
|
# 如果解析失败,使用默认值
|
|
1077
1046
|
if not title:
|
|
1078
1047
|
title = f"Auto-coder: {original_query[:50]}..."
|
|
1079
1048
|
if not body:
|
|
1080
1049
|
body = f"This PR was automatically generated by Auto-coder.\n\nOriginal request: {original_query}"
|
|
1081
|
-
|
|
1050
|
+
|
|
1082
1051
|
return title, body
|
|
1083
|
-
|
|
1052
|
+
|
|
1084
1053
|
except Exception as e:
|
|
1085
1054
|
# 如果 LLM 生成失败,使用默认值
|
|
1086
1055
|
title = f"Auto-coder: {original_query[:50]}..."
|
|
@@ -1089,351 +1058,34 @@ BODY: [描述内容]
|
|
|
1089
1058
|
|
|
1090
1059
|
|
|
1091
1060
|
def add_files(args: List[str]):
|
|
1061
|
+
"""
|
|
1062
|
+
处理文件添加命令,使用 AddFilesHandler 进行统一处理
|
|
1092
1063
|
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
memory["current_files"]["groups_info"] = {}
|
|
1098
|
-
if "current_groups" not in memory["current_files"]:
|
|
1099
|
-
memory["current_files"]["current_groups"] = []
|
|
1100
|
-
groups = memory["current_files"]["groups"]
|
|
1101
|
-
groups_info = memory["current_files"]["groups_info"]
|
|
1102
|
-
|
|
1103
|
-
console = Console()
|
|
1104
|
-
printer = Printer()
|
|
1105
|
-
|
|
1106
|
-
if not args:
|
|
1107
|
-
printer.print_in_terminal("add_files_no_args", style="red")
|
|
1108
|
-
result_manager.append(content=printer.get_message_from_key("add_files_no_args"),
|
|
1109
|
-
meta={"action": "add_files","success":False, "input":{ "args": args}})
|
|
1110
|
-
return
|
|
1111
|
-
|
|
1112
|
-
if args[0] == "/refresh":
|
|
1113
|
-
completer.refresh_files()
|
|
1114
|
-
load_memory()
|
|
1115
|
-
console.print(
|
|
1116
|
-
Panel("Refreshed file list.",
|
|
1117
|
-
title="Files Refreshed", border_style="green")
|
|
1118
|
-
)
|
|
1119
|
-
result_manager.append(content="Files refreshed.",
|
|
1120
|
-
meta={"action": "add_files","success":True, "input":{ "args": args}})
|
|
1121
|
-
return
|
|
1122
|
-
|
|
1123
|
-
if args[0] == "/group":
|
|
1124
|
-
if len(args) == 1 or (len(args) == 2 and args[1] == "list"):
|
|
1125
|
-
if not groups:
|
|
1126
|
-
console.print(
|
|
1127
|
-
Panel("No groups defined.", title="Groups",
|
|
1128
|
-
border_style="yellow")
|
|
1129
|
-
)
|
|
1130
|
-
result_manager.append(content="No groups defined.",
|
|
1131
|
-
meta={"action": "add_files","success":False, "input":{ "args": args}})
|
|
1132
|
-
else:
|
|
1133
|
-
table = Table(
|
|
1134
|
-
title="Defined Groups",
|
|
1135
|
-
show_header=True,
|
|
1136
|
-
header_style="bold magenta",
|
|
1137
|
-
show_lines=True,
|
|
1138
|
-
)
|
|
1139
|
-
table.add_column("Group Name", style="cyan", no_wrap=True)
|
|
1140
|
-
table.add_column("Files", style="green")
|
|
1141
|
-
table.add_column("Query Prefix", style="yellow")
|
|
1142
|
-
table.add_column("Active", style="magenta")
|
|
1143
|
-
|
|
1144
|
-
for i, (group_name, files) in enumerate(groups.items()):
|
|
1145
|
-
query_prefix = groups_info.get(group_name, {}).get(
|
|
1146
|
-
"query_prefix", ""
|
|
1147
|
-
)
|
|
1148
|
-
is_active = (
|
|
1149
|
-
"✓"
|
|
1150
|
-
if group_name in memory["current_files"]["current_groups"]
|
|
1151
|
-
else ""
|
|
1152
|
-
)
|
|
1153
|
-
table.add_row(
|
|
1154
|
-
group_name,
|
|
1155
|
-
"\n".join([os.path.relpath(f, project_root)
|
|
1156
|
-
for f in files]),
|
|
1157
|
-
query_prefix,
|
|
1158
|
-
is_active,
|
|
1159
|
-
end_section=(i == len(groups) - 1),
|
|
1160
|
-
)
|
|
1161
|
-
console.print(Panel(table, border_style="blue"))
|
|
1162
|
-
result_manager.append(content="Defined groups.",
|
|
1163
|
-
meta={"action": "add_files","success":True, "input":{ "args": args}})
|
|
1164
|
-
elif len(args) >= 2 and args[1] == "/reset":
|
|
1165
|
-
memory["current_files"]["current_groups"] = []
|
|
1166
|
-
console.print(
|
|
1167
|
-
Panel(
|
|
1168
|
-
"Active group names have been reset. If you want to clear the active files, you should use the command /remove_files /all.",
|
|
1169
|
-
title="Groups Reset",
|
|
1170
|
-
border_style="green",
|
|
1171
|
-
)
|
|
1172
|
-
)
|
|
1173
|
-
result_manager.append(content="Active group names have been reset. If you want to clear the active files, you should use the command /remove_files /all.",
|
|
1174
|
-
meta={"action": "add_files","success":True, "input":{ "args": args}})
|
|
1175
|
-
elif len(args) >= 3 and args[1] == "/add":
|
|
1176
|
-
group_name = args[2]
|
|
1177
|
-
groups[group_name] = memory["current_files"]["files"].copy()
|
|
1178
|
-
console.print(
|
|
1179
|
-
Panel(
|
|
1180
|
-
f"Added group '{group_name}' with current files.",
|
|
1181
|
-
title="Group Added",
|
|
1182
|
-
border_style="green",
|
|
1183
|
-
)
|
|
1184
|
-
)
|
|
1185
|
-
result_manager.append(content=f"Added group '{group_name}' with current files.",
|
|
1186
|
-
meta={"action": "add_files","success":True, "input":{ "args": args}})
|
|
1187
|
-
|
|
1188
|
-
elif len(args) >= 3 and args[1] == "/drop":
|
|
1189
|
-
group_name = args[2]
|
|
1190
|
-
if group_name in groups:
|
|
1191
|
-
del memory["current_files"]["groups"][group_name]
|
|
1192
|
-
if group_name in groups_info:
|
|
1193
|
-
del memory["current_files"]["groups_info"][group_name]
|
|
1194
|
-
if group_name in memory["current_files"]["current_groups"]:
|
|
1195
|
-
memory["current_files"]["current_groups"].remove(
|
|
1196
|
-
group_name)
|
|
1197
|
-
console.print(
|
|
1198
|
-
Panel(
|
|
1199
|
-
f"Dropped group '{group_name}'.",
|
|
1200
|
-
title="Group Dropped",
|
|
1201
|
-
border_style="green",
|
|
1202
|
-
)
|
|
1203
|
-
)
|
|
1204
|
-
result_manager.append(content=f"Dropped group '{group_name}'.",
|
|
1205
|
-
meta={"action": "add_files","success":True, "input":{ "args": args}})
|
|
1206
|
-
else:
|
|
1207
|
-
console.print(
|
|
1208
|
-
Panel(
|
|
1209
|
-
f"Group '{group_name}' not found.",
|
|
1210
|
-
title="Error",
|
|
1211
|
-
border_style="red",
|
|
1212
|
-
)
|
|
1213
|
-
)
|
|
1214
|
-
result_manager.append(content=f"Group '{group_name}' not found.",
|
|
1215
|
-
meta={"action": "add_files","success":False, "input":{ "args": args}})
|
|
1216
|
-
elif len(args) == 3 and args[1] == "/set":
|
|
1217
|
-
group_name = args[2]
|
|
1218
|
-
|
|
1219
|
-
def multiline_edit():
|
|
1220
|
-
from prompt_toolkit.lexers import PygmentsLexer
|
|
1221
|
-
from pygments.lexers.markup import MarkdownLexer
|
|
1222
|
-
from prompt_toolkit.formatted_text import HTML
|
|
1223
|
-
from prompt_toolkit.shortcuts import print_formatted_text
|
|
1224
|
-
|
|
1225
|
-
style = Style.from_dict(
|
|
1226
|
-
{
|
|
1227
|
-
"dialog": "bg:#88ff88",
|
|
1228
|
-
"dialog frame.label": "bg:#ffffff #000000",
|
|
1229
|
-
"dialog.body": "bg:#000000 #00ff00",
|
|
1230
|
-
"dialog shadow": "bg:#00aa00",
|
|
1231
|
-
}
|
|
1232
|
-
)
|
|
1233
|
-
|
|
1234
|
-
print_formatted_text(
|
|
1235
|
-
HTML(
|
|
1236
|
-
"<b>Type Atom Group Desc (Prese [Esc] + [Enter] to finish.)</b><br/>"
|
|
1237
|
-
)
|
|
1238
|
-
)
|
|
1239
|
-
text = prompt(
|
|
1240
|
-
HTML("<ansicyan>║</ansicyan> "),
|
|
1241
|
-
multiline=True,
|
|
1242
|
-
lexer=PygmentsLexer(MarkdownLexer),
|
|
1243
|
-
style=style,
|
|
1244
|
-
wrap_lines=True,
|
|
1245
|
-
prompt_continuation=HTML("<ansicyan>║</ansicyan> "),
|
|
1246
|
-
rprompt=HTML("<ansicyan>║</ansicyan>"),
|
|
1247
|
-
)
|
|
1248
|
-
return text
|
|
1249
|
-
|
|
1250
|
-
query_prefix = multiline_edit()
|
|
1251
|
-
if group_name in groups:
|
|
1252
|
-
groups_info[group_name] = {"query_prefix": query_prefix}
|
|
1253
|
-
console.print(
|
|
1254
|
-
Panel(
|
|
1255
|
-
f"Set Atom Group Desc for group '{group_name}'.",
|
|
1256
|
-
title="Group Info Updated",
|
|
1257
|
-
border_style="green",
|
|
1258
|
-
)
|
|
1259
|
-
)
|
|
1260
|
-
else:
|
|
1261
|
-
console.print(
|
|
1262
|
-
Panel(
|
|
1263
|
-
f"Group '{group_name}' not found.",
|
|
1264
|
-
title="Error",
|
|
1265
|
-
border_style="red",
|
|
1266
|
-
)
|
|
1267
|
-
)
|
|
1268
|
-
elif len(args) >= 2:
|
|
1269
|
-
# 支持多个组的合并,允许组名之间使用逗号或空格分隔
|
|
1270
|
-
group_names = " ".join(args[1:]).replace(",", " ").split()
|
|
1271
|
-
merged_files = set()
|
|
1272
|
-
missing_groups = []
|
|
1273
|
-
for group_name in group_names:
|
|
1274
|
-
if group_name in groups:
|
|
1275
|
-
merged_files.update(groups[group_name])
|
|
1276
|
-
else:
|
|
1277
|
-
missing_groups.append(group_name)
|
|
1278
|
-
|
|
1279
|
-
if missing_groups:
|
|
1280
|
-
console.print(
|
|
1281
|
-
Panel(
|
|
1282
|
-
f"Group(s) not found: {', '.join(missing_groups)}",
|
|
1283
|
-
title="Error",
|
|
1284
|
-
border_style="red",
|
|
1285
|
-
)
|
|
1286
|
-
)
|
|
1287
|
-
result_manager.append(content=f"Group(s) not found: {', '.join(missing_groups)}",
|
|
1288
|
-
meta={"action": "add_files","success":False, "input":{ "args": args}})
|
|
1289
|
-
|
|
1290
|
-
if merged_files:
|
|
1291
|
-
memory["current_files"]["files"] = list(merged_files)
|
|
1292
|
-
memory["current_files"]["current_groups"] = [
|
|
1293
|
-
name for name in group_names if name in groups
|
|
1294
|
-
]
|
|
1295
|
-
console.print(
|
|
1296
|
-
Panel(
|
|
1297
|
-
f"Merged files from groups: {', '.join(group_names)}",
|
|
1298
|
-
title="Files Merged",
|
|
1299
|
-
border_style="green",
|
|
1300
|
-
)
|
|
1301
|
-
)
|
|
1302
|
-
table = Table(
|
|
1303
|
-
title="Current Files",
|
|
1304
|
-
show_header=True,
|
|
1305
|
-
header_style="bold magenta",
|
|
1306
|
-
show_lines=True, # 这会在每行之间添加分割线
|
|
1307
|
-
)
|
|
1308
|
-
table.add_column("File", style="green")
|
|
1309
|
-
for i, f in enumerate(memory["current_files"]["files"]):
|
|
1310
|
-
table.add_row(
|
|
1311
|
-
os.path.relpath(f, project_root),
|
|
1312
|
-
end_section=(
|
|
1313
|
-
i == len(memory["current_files"]["files"]) - 1
|
|
1314
|
-
), # 在最后一行之后不添加分割线
|
|
1315
|
-
)
|
|
1316
|
-
console.print(Panel(table, border_style="blue"))
|
|
1317
|
-
console.print(
|
|
1318
|
-
Panel(
|
|
1319
|
-
f"Active groups: {', '.join(memory['current_files']['current_groups'])}",
|
|
1320
|
-
title="Active Groups",
|
|
1321
|
-
border_style="green",
|
|
1322
|
-
)
|
|
1323
|
-
)
|
|
1324
|
-
result_manager.append(content=f"Active groups: {', '.join(memory['current_files']['current_groups'])}",
|
|
1325
|
-
meta={"action": "add_files","success":True, "input":{ "args": args}})
|
|
1326
|
-
elif not missing_groups:
|
|
1327
|
-
console.print(
|
|
1328
|
-
Panel(
|
|
1329
|
-
"No files in the specified groups.",
|
|
1330
|
-
title="No Files Added",
|
|
1331
|
-
border_style="yellow",
|
|
1332
|
-
)
|
|
1333
|
-
)
|
|
1334
|
-
result_manager.append(content="No files in the specified groups.",
|
|
1335
|
-
meta={"action": "add_files","success":False, "input":{ "args": args}})
|
|
1336
|
-
else:
|
|
1337
|
-
existing_files = memory["current_files"]["files"]
|
|
1338
|
-
matched_files = find_files_in_project(args)
|
|
1339
|
-
|
|
1340
|
-
files_to_add = [f for f in matched_files if f not in existing_files]
|
|
1341
|
-
if files_to_add:
|
|
1342
|
-
memory["current_files"]["files"].extend(files_to_add)
|
|
1343
|
-
table = Table(
|
|
1344
|
-
title=get_message("add_files_added_files"),
|
|
1345
|
-
show_header=True,
|
|
1346
|
-
header_style="bold magenta",
|
|
1347
|
-
show_lines=True, # 这会在每行之间添加分割线
|
|
1348
|
-
)
|
|
1349
|
-
table.add_column("File", style="green")
|
|
1350
|
-
for i, f in enumerate(files_to_add):
|
|
1351
|
-
table.add_row(
|
|
1352
|
-
os.path.relpath(f, project_root),
|
|
1353
|
-
end_section=(
|
|
1354
|
-
i == len(files_to_add) - 1
|
|
1355
|
-
), # 在最后一行之后不添加分割线
|
|
1356
|
-
)
|
|
1357
|
-
console.print(Panel(table, border_style="green"))
|
|
1358
|
-
result_manager.append(content=f"Added files: {', '.join(files_to_add)}",
|
|
1359
|
-
meta={"action": "add_files","success":True, "input":{ "args": args}})
|
|
1360
|
-
else:
|
|
1361
|
-
printer.print_in_terminal("add_files_matched", style="yellow")
|
|
1362
|
-
result_manager.append(content=f"No files matched.",
|
|
1363
|
-
meta={"action": "add_files","success":False, "input":{ "args": args}})
|
|
1064
|
+
Args:
|
|
1065
|
+
args: 命令参数列表
|
|
1066
|
+
"""
|
|
1067
|
+
from autocoder.common.file_handler import AddFilesHandler
|
|
1364
1068
|
|
|
1365
|
-
|
|
1069
|
+
handler = AddFilesHandler()
|
|
1070
|
+
handler.handle_add_files_command(args)
|
|
1366
1071
|
|
|
1367
1072
|
|
|
1368
1073
|
def remove_files(file_names: List[str]):
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
result_manager = ResultManager()
|
|
1074
|
+
"""
|
|
1075
|
+
处理文件删除命令,使用 RemoveFilesHandler 进行统一处理
|
|
1372
1076
|
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
result_manager.append(content="All files removed.",
|
|
1378
|
-
meta={"action": "remove_files","success":True, "input":{ "file_names": file_names}})
|
|
1379
|
-
else:
|
|
1380
|
-
files_to_remove = set()
|
|
1381
|
-
current_files_abs = memory["current_files"]["files"]
|
|
1382
|
-
|
|
1383
|
-
for pattern in file_names:
|
|
1384
|
-
pattern = pattern.strip() # Remove leading/trailing whitespace
|
|
1385
|
-
if not pattern:
|
|
1386
|
-
continue
|
|
1387
|
-
|
|
1388
|
-
is_wildcard = "*" in pattern or "?" in pattern
|
|
1389
|
-
|
|
1390
|
-
for file_path_abs in current_files_abs:
|
|
1391
|
-
relative_path = os.path.relpath(file_path_abs, project_root)
|
|
1392
|
-
basename = os.path.basename(file_path_abs)
|
|
1393
|
-
|
|
1394
|
-
matched = False
|
|
1395
|
-
if is_wildcard:
|
|
1396
|
-
# Match pattern against relative path or basename
|
|
1397
|
-
if fnmatch.fnmatch(relative_path, pattern) or fnmatch.fnmatch(basename, pattern):
|
|
1398
|
-
matched = True
|
|
1399
|
-
else:
|
|
1400
|
-
# Exact match against relative path, absolute path, or basename
|
|
1401
|
-
if relative_path == pattern or file_path_abs == pattern or basename == pattern:
|
|
1402
|
-
matched = True
|
|
1403
|
-
|
|
1404
|
-
if matched:
|
|
1405
|
-
files_to_remove.add(file_path_abs)
|
|
1406
|
-
|
|
1407
|
-
removed_files_list = list(files_to_remove)
|
|
1408
|
-
if removed_files_list:
|
|
1409
|
-
# Update memory by filtering out the files to remove
|
|
1410
|
-
memory["current_files"]["files"] = [
|
|
1411
|
-
f for f in current_files_abs if f not in files_to_remove
|
|
1412
|
-
]
|
|
1077
|
+
Args:
|
|
1078
|
+
file_names: 文件名列表或模式列表
|
|
1079
|
+
"""
|
|
1080
|
+
from autocoder.common.file_handler import RemoveFilesHandler
|
|
1413
1081
|
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
header_style="bold magenta"
|
|
1417
|
-
)
|
|
1418
|
-
table.add_column(printer.get_message_from_key("file_column_title"), style="green")
|
|
1419
|
-
for f in removed_files_list:
|
|
1420
|
-
table.add_row(os.path.relpath(f, project_root))
|
|
1082
|
+
handler = RemoveFilesHandler()
|
|
1083
|
+
handler.handle_remove_files_command(file_names)
|
|
1421
1084
|
|
|
1422
|
-
console = Console()
|
|
1423
|
-
console.print(
|
|
1424
|
-
Panel(table, border_style="green",
|
|
1425
|
-
title=printer.get_message_from_key("files_removed")))
|
|
1426
|
-
result_manager.append(content=f"Removed files: {', '.join(removed_files_list)}",
|
|
1427
|
-
meta={"action": "remove_files","success":True, "input":{ "file_names": file_names}})
|
|
1428
|
-
else:
|
|
1429
|
-
printer.print_in_terminal("remove_files_none", style="yellow")
|
|
1430
|
-
result_manager.append(content=printer.get_message_from_key("remove_files_none"),
|
|
1431
|
-
meta={"action": "remove_files","success":False, "input":{ "file_names": file_names}})
|
|
1432
|
-
save_memory()
|
|
1433
1085
|
|
|
1434
|
-
@run_in_raw_thread()
|
|
1435
1086
|
def ask(query: str):
|
|
1436
|
-
|
|
1087
|
+
memory_manager = get_memory_manager()
|
|
1088
|
+
conf = memory_manager.get_all_config()
|
|
1437
1089
|
yaml_config = {
|
|
1438
1090
|
"include_file": ["./base/base.yml"],
|
|
1439
1091
|
}
|
|
@@ -1461,7 +1113,7 @@ def ask(query: str):
|
|
|
1461
1113
|
|
|
1462
1114
|
execute_file = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
1463
1115
|
|
|
1464
|
-
with open(os.path.join(execute_file), "w",encoding="utf-8") as f:
|
|
1116
|
+
with open(os.path.join(execute_file), "w", encoding="utf-8") as f:
|
|
1465
1117
|
f.write(yaml_content)
|
|
1466
1118
|
|
|
1467
1119
|
def execute_ask():
|
|
@@ -1476,50 +1128,27 @@ def ask(query: str):
|
|
|
1476
1128
|
def get_llm_friendly_package_docs(
|
|
1477
1129
|
package_name: Optional[str] = None, return_paths: bool = False
|
|
1478
1130
|
) -> List[str]:
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
return
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
if os.path.isdir(username_path):
|
|
1494
|
-
for lib_name in os.listdir(username_path):
|
|
1495
|
-
lib_path = os.path.join(username_path, lib_name)
|
|
1496
|
-
if (
|
|
1497
|
-
os.path.isdir(lib_path)
|
|
1498
|
-
and (
|
|
1499
|
-
package_name is None
|
|
1500
|
-
or lib_name == package_name
|
|
1501
|
-
or package_name == os.path.join(username, lib_name)
|
|
1502
|
-
)
|
|
1503
|
-
and lib_name in libs
|
|
1504
|
-
):
|
|
1505
|
-
for root, _, files in os.walk(lib_path):
|
|
1506
|
-
for file in files:
|
|
1507
|
-
if file.endswith(".md"):
|
|
1508
|
-
file_path = os.path.join(root, file)
|
|
1509
|
-
if return_paths:
|
|
1510
|
-
docs.append(file_path)
|
|
1511
|
-
else:
|
|
1512
|
-
with open(file_path, "r",encoding="utf-8") as f:
|
|
1513
|
-
docs.append(f.read())
|
|
1514
|
-
|
|
1515
|
-
return docs
|
|
1131
|
+
"""
|
|
1132
|
+
Get LLM friendly package documentation using the new AC module system
|
|
1133
|
+
|
|
1134
|
+
Args:
|
|
1135
|
+
package_name: Specific package name to get docs for, None for all packages
|
|
1136
|
+
return_paths: If True, return file paths; if False, return file contents
|
|
1137
|
+
|
|
1138
|
+
Returns:
|
|
1139
|
+
List of documentation content or file paths
|
|
1140
|
+
"""
|
|
1141
|
+
from autocoder.common.llm_friendly_package import get_package_manager
|
|
1142
|
+
|
|
1143
|
+
package_manager = get_package_manager()
|
|
1144
|
+
return package_manager.get_docs(package_name, return_paths)
|
|
1516
1145
|
|
|
1517
1146
|
|
|
1518
1147
|
def convert_yaml_to_config(yaml_file: str):
|
|
1519
1148
|
from autocoder.auto_coder import AutoCoderArgs, load_include_files, Template
|
|
1520
1149
|
|
|
1521
1150
|
args = AutoCoderArgs()
|
|
1522
|
-
with open(yaml_file, "r",encoding="utf-8") as f:
|
|
1151
|
+
with open(yaml_file, "r", encoding="utf-8") as f:
|
|
1523
1152
|
config = yaml.safe_load(f)
|
|
1524
1153
|
config = load_include_files(config, yaml_file)
|
|
1525
1154
|
for key, value in config.items():
|
|
@@ -1531,150 +1160,22 @@ def convert_yaml_to_config(yaml_file: str):
|
|
|
1531
1160
|
setattr(args, key, value)
|
|
1532
1161
|
return args
|
|
1533
1162
|
|
|
1534
|
-
@run_in_raw_thread()
|
|
1535
|
-
def mcp(query: str):
|
|
1536
|
-
query = query.strip()
|
|
1537
|
-
mcp_server = get_mcp_server()
|
|
1538
|
-
printer = Printer()
|
|
1539
|
-
|
|
1540
|
-
# Handle remove command
|
|
1541
|
-
if query.startswith("/remove"):
|
|
1542
|
-
server_name = query.replace("/remove", "", 1).strip()
|
|
1543
|
-
response = mcp_server.send_request(
|
|
1544
|
-
McpRemoveRequest(server_name=server_name))
|
|
1545
|
-
if response.error:
|
|
1546
|
-
printer.print_in_terminal("mcp_remove_error", style="red", error=response.error)
|
|
1547
|
-
else:
|
|
1548
|
-
printer.print_in_terminal("mcp_remove_success", style="green", result=response.result)
|
|
1549
|
-
return
|
|
1550
|
-
|
|
1551
|
-
# Handle list command
|
|
1552
|
-
if query.startswith("/list_running"):
|
|
1553
|
-
response = mcp_server.send_request(McpListRunningRequest())
|
|
1554
|
-
if response.error:
|
|
1555
|
-
printer.print_in_terminal("mcp_list_running_error", style="red", error=response.error)
|
|
1556
|
-
else:
|
|
1557
|
-
printer.print_in_terminal("mcp_list_running_title")
|
|
1558
|
-
printer.print_str_in_terminal(response.result)
|
|
1559
|
-
return
|
|
1560
|
-
|
|
1561
|
-
# Handle list command
|
|
1562
|
-
if query.startswith("/list"):
|
|
1563
|
-
response = mcp_server.send_request(McpListRequest())
|
|
1564
|
-
if response.error:
|
|
1565
|
-
printer.print_in_terminal("mcp_list_builtin_error", style="red", error=response.error)
|
|
1566
|
-
else:
|
|
1567
|
-
printer.print_in_terminal("mcp_list_builtin_title")
|
|
1568
|
-
printer.print_str_in_terminal(response.result)
|
|
1569
|
-
return
|
|
1570
|
-
|
|
1571
|
-
# Handle refresh command
|
|
1572
|
-
if query.startswith("/refresh"):
|
|
1573
|
-
server_name = query.replace("/refresh", "", 1).strip()
|
|
1574
|
-
response = mcp_server.send_request(McpRefreshRequest(name=server_name or None))
|
|
1575
|
-
if response.error:
|
|
1576
|
-
printer.print_in_terminal("mcp_refresh_error", style="red", error=response.error)
|
|
1577
|
-
else:
|
|
1578
|
-
printer.print_in_terminal("mcp_refresh_success", style="green")
|
|
1579
|
-
return
|
|
1580
|
-
|
|
1581
|
-
# Handle add command
|
|
1582
|
-
if query.startswith("/add"):
|
|
1583
|
-
query = query.replace("/add", "", 1).strip()
|
|
1584
|
-
request = McpInstallRequest(server_name_or_config=query)
|
|
1585
|
-
response = mcp_server.send_request(request)
|
|
1586
|
-
|
|
1587
|
-
if response.error:
|
|
1588
|
-
printer.print_in_terminal("mcp_install_error", style="red", error=response.error)
|
|
1589
|
-
else:
|
|
1590
|
-
printer.print_in_terminal("mcp_install_success", style="green", result=response.result)
|
|
1591
|
-
return
|
|
1592
|
-
|
|
1593
|
-
# Handle default query
|
|
1594
|
-
conf = memory.get("conf", {})
|
|
1595
|
-
yaml_config = {
|
|
1596
|
-
"include_file": ["./base/base.yml"],
|
|
1597
|
-
"auto_merge": conf.get("auto_merge", "editblock"),
|
|
1598
|
-
"human_as_model": conf.get("human_as_model", "false") == "true",
|
|
1599
|
-
"skip_build_index": conf.get("skip_build_index", "true") == "true",
|
|
1600
|
-
"skip_confirm": conf.get("skip_confirm", "true") == "true",
|
|
1601
|
-
"silence": conf.get("silence", "true") == "true",
|
|
1602
|
-
"include_project_structure": conf.get("include_project_structure", "true")
|
|
1603
|
-
== "true",
|
|
1604
|
-
"exclude_files": memory.get("exclude_files", []),
|
|
1605
|
-
}
|
|
1606
|
-
for key, value in conf.items():
|
|
1607
|
-
converted_value = convert_config_value(key, value)
|
|
1608
|
-
if converted_value is not None:
|
|
1609
|
-
yaml_config[key] = converted_value
|
|
1610
|
-
|
|
1611
|
-
temp_yaml = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
1612
|
-
try:
|
|
1613
|
-
with open(temp_yaml, "w",encoding="utf-8") as f:
|
|
1614
|
-
f.write(convert_yaml_config_to_str(yaml_config=yaml_config))
|
|
1615
|
-
args = convert_yaml_to_config(temp_yaml)
|
|
1616
|
-
finally:
|
|
1617
|
-
if os.path.exists(temp_yaml):
|
|
1618
|
-
os.remove(temp_yaml)
|
|
1619
|
-
|
|
1620
|
-
mcp_server = get_mcp_server()
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
if query.startswith("/info"):
|
|
1624
|
-
response = mcp_server.send_request(McpServerInfoRequest(
|
|
1625
|
-
model=args.inference_model or args.model,
|
|
1626
|
-
product_mode=args.product_mode
|
|
1627
|
-
))
|
|
1628
|
-
if response.error:
|
|
1629
|
-
printer.print_in_terminal("mcp_server_info_error", style="red", error=response.error)
|
|
1630
|
-
else:
|
|
1631
|
-
printer.print_in_terminal("mcp_server_info_title")
|
|
1632
|
-
printer.print_str_in_terminal(response.result)
|
|
1633
|
-
return
|
|
1634
|
-
|
|
1635
|
-
response = mcp_server.send_request(
|
|
1636
|
-
McpRequest(
|
|
1637
|
-
query=query,
|
|
1638
|
-
model=args.inference_model or args.model,
|
|
1639
|
-
product_mode=args.product_mode
|
|
1640
|
-
)
|
|
1641
|
-
)
|
|
1642
|
-
|
|
1643
|
-
if response.error:
|
|
1644
|
-
printer.print_panel(
|
|
1645
|
-
f"Error from MCP server: {response.error}",
|
|
1646
|
-
text_options={"justify": "left"},
|
|
1647
|
-
panel_options={
|
|
1648
|
-
"title": printer.get_message_from_key("mcp_error_title"),
|
|
1649
|
-
"border_style": "red"
|
|
1650
|
-
}
|
|
1651
|
-
)
|
|
1652
|
-
else:
|
|
1653
|
-
# Save conversation
|
|
1654
|
-
mcp_dir = os.path.join(".auto-coder", "mcp", "conversations")
|
|
1655
|
-
os.makedirs(mcp_dir, exist_ok=True)
|
|
1656
|
-
timestamp = str(int(time.time()))
|
|
1657
|
-
file_path = os.path.join(mcp_dir, f"{timestamp}.md")
|
|
1658
1163
|
|
|
1659
|
-
|
|
1660
|
-
|
|
1164
|
+
def mcp(query: str):
|
|
1165
|
+
"""
|
|
1166
|
+
处理MCP命令,使用 McpHandler 进行统一处理
|
|
1661
1167
|
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1168
|
+
Args:
|
|
1169
|
+
query: 查询字符串
|
|
1170
|
+
"""
|
|
1171
|
+
from autocoder.common.file_handler import McpHandler
|
|
1665
1172
|
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
Panel(
|
|
1669
|
-
Markdown(markdown_content, justify="left"),
|
|
1670
|
-
title=printer.get_message_from_key('mcp_response_title'),
|
|
1671
|
-
border_style="green"
|
|
1672
|
-
)
|
|
1673
|
-
)
|
|
1173
|
+
handler = McpHandler()
|
|
1174
|
+
handler.handle_mcp_command(query)
|
|
1674
1175
|
|
|
1675
1176
|
|
|
1676
|
-
@run_in_raw_thread()
|
|
1677
1177
|
def code_next(query: str):
|
|
1178
|
+
memory = get_current_memory()
|
|
1678
1179
|
conf = memory.get("conf", {})
|
|
1679
1180
|
yaml_config = {
|
|
1680
1181
|
"include_file": ["./base/base.yml"],
|
|
@@ -1683,7 +1184,7 @@ def code_next(query: str):
|
|
|
1683
1184
|
"skip_build_index": conf.get("skip_build_index", "true") == "true",
|
|
1684
1185
|
"skip_confirm": conf.get("skip_confirm", "true") == "true",
|
|
1685
1186
|
"silence": conf.get("silence", "true") == "true",
|
|
1686
|
-
"include_project_structure": conf.get("include_project_structure", "
|
|
1187
|
+
"include_project_structure": conf.get("include_project_structure", "false")
|
|
1687
1188
|
== "true",
|
|
1688
1189
|
"exclude_files": memory.get("exclude_files", []),
|
|
1689
1190
|
}
|
|
@@ -1694,7 +1195,7 @@ def code_next(query: str):
|
|
|
1694
1195
|
|
|
1695
1196
|
temp_yaml = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
1696
1197
|
try:
|
|
1697
|
-
with open(temp_yaml, "w",encoding="utf-8") as f:
|
|
1198
|
+
with open(temp_yaml, "w", encoding="utf-8") as f:
|
|
1698
1199
|
f.write(convert_yaml_config_to_str(yaml_config=yaml_config))
|
|
1699
1200
|
args = convert_yaml_to_config(temp_yaml)
|
|
1700
1201
|
finally:
|
|
@@ -1704,8 +1205,7 @@ def code_next(query: str):
|
|
|
1704
1205
|
product_mode = conf.get("product_mode", "lite")
|
|
1705
1206
|
llm = get_single_llm(args.chat_model or args.model, product_mode=product_mode)
|
|
1706
1207
|
|
|
1707
|
-
auto_guesser = AutoGuessQuery(
|
|
1708
|
-
llm=llm, project_dir=os.getcwd(), skip_diff=True)
|
|
1208
|
+
auto_guesser = AutoGuessQuery(llm=llm, project_dir=os.getcwd(), skip_diff=True)
|
|
1709
1209
|
|
|
1710
1210
|
predicted_tasks = auto_guesser.predict_next_tasks(
|
|
1711
1211
|
5, is_human_as_model=args.human_as_model
|
|
@@ -1719,25 +1219,20 @@ def code_next(query: str):
|
|
|
1719
1219
|
console = Console()
|
|
1720
1220
|
|
|
1721
1221
|
# Create main panel for all predicted tasks
|
|
1722
|
-
table = Table(show_header=True,
|
|
1723
|
-
header_style="bold magenta", show_lines=True)
|
|
1222
|
+
table = Table(show_header=True, header_style="bold magenta", show_lines=True)
|
|
1724
1223
|
table.add_column("Priority", style="cyan", width=8)
|
|
1725
|
-
table.add_column("Task Description", style="green",
|
|
1726
|
-
width=40, overflow="fold")
|
|
1224
|
+
table.add_column("Task Description", style="green", width=40, overflow="fold")
|
|
1727
1225
|
table.add_column("Files", style="yellow", width=30, overflow="fold")
|
|
1728
1226
|
table.add_column("Reason", style="blue", width=30, overflow="fold")
|
|
1729
|
-
table.add_column("Dependencies", style="magenta",
|
|
1730
|
-
width=30, overflow="fold")
|
|
1227
|
+
table.add_column("Dependencies", style="magenta", width=30, overflow="fold")
|
|
1731
1228
|
|
|
1732
1229
|
for task in predicted_tasks:
|
|
1733
1230
|
# Format file paths to be more readable
|
|
1734
|
-
file_list = "\n".join([os.path.relpath(f, os.getcwd())
|
|
1735
|
-
for f in task.urls])
|
|
1231
|
+
file_list = "\n".join([os.path.relpath(f, os.getcwd()) for f in task.urls])
|
|
1736
1232
|
|
|
1737
1233
|
# Format dependencies to be more readable
|
|
1738
1234
|
dependencies = (
|
|
1739
|
-
"\n".join(
|
|
1740
|
-
task.dependency_queries) if task.dependency_queries else "None"
|
|
1235
|
+
"\n".join(task.dependency_queries) if task.dependency_queries else "None"
|
|
1741
1236
|
)
|
|
1742
1237
|
|
|
1743
1238
|
table.add_row(
|
|
@@ -1754,260 +1249,42 @@ def code_next(query: str):
|
|
|
1754
1249
|
)
|
|
1755
1250
|
|
|
1756
1251
|
|
|
1757
|
-
@run_in_raw_thread()
|
|
1758
1252
|
def commit(query: Optional[str] = None):
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
def prepare_commit_yaml():
|
|
1762
|
-
auto_coder_main(["next", "chat_action"])
|
|
1763
|
-
|
|
1764
|
-
prepare_commit_yaml()
|
|
1765
|
-
|
|
1766
|
-
# no_diff = query.strip().startswith("/no_diff")
|
|
1767
|
-
# if no_diff:
|
|
1768
|
-
# query = query.replace("/no_diff", "", 1).strip()
|
|
1769
|
-
|
|
1770
|
-
latest_yaml_file = get_last_yaml_file("actions")
|
|
1771
|
-
|
|
1772
|
-
conf = memory.get("conf", {})
|
|
1773
|
-
current_files = memory["current_files"]["files"]
|
|
1774
|
-
execute_file = None
|
|
1775
|
-
|
|
1776
|
-
if latest_yaml_file:
|
|
1777
|
-
try:
|
|
1778
|
-
execute_file = os.path.join("actions", latest_yaml_file)
|
|
1779
|
-
yaml_config = {
|
|
1780
|
-
"include_file": ["./base/base.yml"],
|
|
1781
|
-
"auto_merge": conf.get("auto_merge", "editblock"),
|
|
1782
|
-
"human_as_model": conf.get("human_as_model", "false") == "true",
|
|
1783
|
-
"skip_build_index": conf.get("skip_build_index", "true") == "true",
|
|
1784
|
-
"skip_confirm": conf.get("skip_confirm", "true") == "true",
|
|
1785
|
-
"silence": conf.get("silence", "true") == "true",
|
|
1786
|
-
"include_project_structure": conf.get("include_project_structure", "true")
|
|
1787
|
-
== "true",
|
|
1788
|
-
}
|
|
1789
|
-
for key, value in conf.items():
|
|
1790
|
-
converted_value = convert_config_value(key, value)
|
|
1791
|
-
if converted_value is not None:
|
|
1792
|
-
yaml_config[key] = converted_value
|
|
1793
|
-
|
|
1794
|
-
yaml_config["urls"] = current_files + get_llm_friendly_package_docs(
|
|
1795
|
-
return_paths=True
|
|
1796
|
-
)
|
|
1797
|
-
|
|
1798
|
-
if conf.get("enable_global_memory", "false") in ["true", "True",True]:
|
|
1799
|
-
yaml_config["urls"] += get_global_memory_file_paths()
|
|
1800
|
-
|
|
1801
|
-
# 临时保存yaml文件,然后读取yaml文件,转换为args
|
|
1802
|
-
temp_yaml = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
1803
|
-
try:
|
|
1804
|
-
with open(temp_yaml, "w",encoding="utf-8") as f:
|
|
1805
|
-
f.write(convert_yaml_config_to_str(
|
|
1806
|
-
yaml_config=yaml_config))
|
|
1807
|
-
args = convert_yaml_to_config(temp_yaml)
|
|
1808
|
-
finally:
|
|
1809
|
-
if os.path.exists(temp_yaml):
|
|
1810
|
-
os.remove(temp_yaml)
|
|
1811
|
-
|
|
1812
|
-
target_model = args.commit_model or args.model
|
|
1813
|
-
llm = get_single_llm(target_model, product_mode)
|
|
1814
|
-
printer = Printer()
|
|
1815
|
-
printer.print_in_terminal("commit_generating", style="yellow", model_name=target_model)
|
|
1816
|
-
commit_message = ""
|
|
1817
|
-
|
|
1818
|
-
try:
|
|
1819
|
-
uncommitted_changes = git_utils.get_uncommitted_changes(".")
|
|
1820
|
-
commit_message = git_utils.generate_commit_message.with_llm(llm).run(
|
|
1821
|
-
uncommitted_changes, query=query
|
|
1822
|
-
)
|
|
1823
|
-
# memory["conversation"].append(
|
|
1824
|
-
# {"role": "user", "content": commit_message})
|
|
1825
|
-
except Exception as e:
|
|
1826
|
-
printer.print_in_terminal("commit_failed", style="red", error=str(e), model_name=target_model)
|
|
1827
|
-
return
|
|
1828
|
-
|
|
1829
|
-
yaml_config["query"] = commit_message
|
|
1830
|
-
yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
|
|
1831
|
-
with open(os.path.join(execute_file), "w",encoding="utf-8") as f:
|
|
1832
|
-
f.write(yaml_content)
|
|
1833
|
-
|
|
1834
|
-
args.file = execute_file
|
|
1835
|
-
|
|
1836
|
-
file_name = os.path.basename(execute_file)
|
|
1837
|
-
commit_result = git_utils.commit_changes(
|
|
1838
|
-
".", f"{commit_message}\nauto_coder_{file_name}"
|
|
1839
|
-
)
|
|
1840
|
-
|
|
1841
|
-
printer = Printer()
|
|
1842
|
-
|
|
1843
|
-
action_yml_file_manager = ActionYmlFileManager(args.source_dir)
|
|
1844
|
-
action_file_name = os.path.basename(args.file)
|
|
1845
|
-
add_updated_urls = []
|
|
1846
|
-
for file in commit_result.changed_files:
|
|
1847
|
-
add_updated_urls.append(os.path.join(args.source_dir, file))
|
|
1848
|
-
|
|
1849
|
-
args.add_updated_urls = add_updated_urls
|
|
1850
|
-
update_yaml_success = action_yml_file_manager.update_yaml_field(action_file_name, "add_updated_urls", add_updated_urls)
|
|
1851
|
-
if not update_yaml_success:
|
|
1852
|
-
printer.print_in_terminal("yaml_save_error", style="red", yaml_file=action_file_name)
|
|
1853
|
-
|
|
1854
|
-
if args.enable_active_context:
|
|
1855
|
-
active_context_manager = ActiveContextManager(llm, args.source_dir)
|
|
1856
|
-
task_id = active_context_manager.process_changes(args)
|
|
1857
|
-
printer.print_in_terminal("active_context_background_task",
|
|
1858
|
-
style="blue",
|
|
1859
|
-
task_id=task_id)
|
|
1860
|
-
git_utils.print_commit_info(commit_result=commit_result)
|
|
1861
|
-
if commit_message:
|
|
1862
|
-
printer.print_in_terminal("commit_message", style="green", model_name=target_model, message=commit_message)
|
|
1863
|
-
except Exception as e:
|
|
1864
|
-
import traceback
|
|
1865
|
-
traceback.print_exc()
|
|
1866
|
-
print(f"Failed to commit: {e}")
|
|
1867
|
-
if execute_file:
|
|
1868
|
-
os.remove(execute_file)
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
@run_in_raw_thread()
|
|
1872
|
-
def coding(query: str):
|
|
1873
|
-
console = Console()
|
|
1874
|
-
is_apply = query.strip().startswith("/apply")
|
|
1875
|
-
if is_apply:
|
|
1876
|
-
query = query.replace("/apply", "", 1).strip()
|
|
1877
|
-
|
|
1878
|
-
is_next = query.strip().startswith("/next")
|
|
1879
|
-
if is_next:
|
|
1880
|
-
query = query.replace("/next", "", 1).strip()
|
|
1881
|
-
|
|
1882
|
-
if is_next:
|
|
1883
|
-
code_next(query)
|
|
1884
|
-
return
|
|
1885
|
-
|
|
1886
|
-
# memory["conversation"].append({"role": "user", "content": query})
|
|
1887
|
-
conf = memory.get("conf", {})
|
|
1888
|
-
|
|
1889
|
-
current_files = memory["current_files"]["files"]
|
|
1890
|
-
current_groups = memory["current_files"].get("current_groups", [])
|
|
1891
|
-
groups = memory["current_files"].get("groups", {})
|
|
1892
|
-
groups_info = memory["current_files"].get("groups_info", {})
|
|
1893
|
-
|
|
1894
|
-
def prepare_chat_yaml():
|
|
1895
|
-
auto_coder_main(["next", "chat_action"])
|
|
1896
|
-
|
|
1897
|
-
prepare_chat_yaml()
|
|
1898
|
-
|
|
1899
|
-
latest_yaml_file = get_last_yaml_file("actions")
|
|
1900
|
-
|
|
1901
|
-
if latest_yaml_file:
|
|
1902
|
-
yaml_config = {
|
|
1903
|
-
"include_file": ["./base/base.yml"],
|
|
1904
|
-
"auto_merge": conf.get("auto_merge", "editblock"),
|
|
1905
|
-
"human_as_model": conf.get("human_as_model", "false") == "true",
|
|
1906
|
-
"skip_build_index": conf.get("skip_build_index", "true") == "true",
|
|
1907
|
-
"skip_confirm": conf.get("skip_confirm", "true") == "true",
|
|
1908
|
-
"silence": conf.get("silence", "true") == "true",
|
|
1909
|
-
"include_project_structure": conf.get("include_project_structure", "true")
|
|
1910
|
-
== "true",
|
|
1911
|
-
"exclude_files": memory.get("exclude_files", []),
|
|
1912
|
-
}
|
|
1913
|
-
|
|
1914
|
-
yaml_config["context"] = ""
|
|
1915
|
-
yaml_config["in_code_apply"] = is_apply
|
|
1916
|
-
|
|
1917
|
-
for key, value in conf.items():
|
|
1918
|
-
converted_value = convert_config_value(key, value)
|
|
1919
|
-
if converted_value is not None:
|
|
1920
|
-
yaml_config[key] = converted_value
|
|
1253
|
+
"""
|
|
1254
|
+
处理提交命令,使用 CommitHandler 进行统一处理
|
|
1921
1255
|
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1256
|
+
Args:
|
|
1257
|
+
query: 可选的提交消息或命令
|
|
1258
|
+
"""
|
|
1259
|
+
from autocoder.common.file_handler import CommitHandler
|
|
1925
1260
|
|
|
1926
|
-
|
|
1927
|
-
|
|
1261
|
+
handler = CommitHandler()
|
|
1262
|
+
handler.handle_commit_command(query)
|
|
1928
1263
|
|
|
1929
|
-
# handle image
|
|
1930
|
-
v = Image.convert_image_paths_from(query)
|
|
1931
|
-
yaml_config["query"] = v
|
|
1932
1264
|
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
for group in current_groups:
|
|
1937
|
-
group_files = groups.get(group, [])
|
|
1938
|
-
query_prefix = groups_info.get(
|
|
1939
|
-
group, {}).get("query_prefix", "")
|
|
1940
|
-
active_groups_context += f"组名: {group}\n"
|
|
1941
|
-
active_groups_context += f"文件列表:\n"
|
|
1942
|
-
for file in group_files:
|
|
1943
|
-
active_groups_context += f"- {file}\n"
|
|
1944
|
-
active_groups_context += f"组描述: {query_prefix}\n\n"
|
|
1945
|
-
|
|
1946
|
-
yaml_config["context"] = active_groups_context + "\n"
|
|
1947
|
-
|
|
1948
|
-
if is_apply:
|
|
1949
|
-
memory_dir = os.path.join(".auto-coder", "memory")
|
|
1950
|
-
os.makedirs(memory_dir, exist_ok=True)
|
|
1951
|
-
memory_file = os.path.join(memory_dir, "chat_history.json")
|
|
1952
|
-
|
|
1953
|
-
def error_message():
|
|
1954
|
-
console.print(
|
|
1955
|
-
Panel(
|
|
1956
|
-
"No chat history found to apply.",
|
|
1957
|
-
title="Chat History",
|
|
1958
|
-
expand=False,
|
|
1959
|
-
border_style="yellow",
|
|
1960
|
-
)
|
|
1961
|
-
)
|
|
1265
|
+
def coding(query: str, cancel_token=None):
|
|
1266
|
+
"""
|
|
1267
|
+
处理代码生成命令,使用 CodingHandler 进行统一处理
|
|
1962
1268
|
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
if not chat_history["ask_conversation"]:
|
|
1969
|
-
error_message()
|
|
1970
|
-
else:
|
|
1971
|
-
conversations = chat_history["ask_conversation"]
|
|
1972
|
-
|
|
1973
|
-
if conversations:
|
|
1974
|
-
yaml_config[
|
|
1975
|
-
"context"
|
|
1976
|
-
] += f"下面是我们的历史对话,参考我们的历史对话从而更好的理解需求和修改代码: \n\n<history>\n"
|
|
1977
|
-
for conv in conversations:
|
|
1978
|
-
if conv["role"] == "user":
|
|
1979
|
-
yaml_config["context"] += f"用户: {conv['content']}\n"
|
|
1980
|
-
elif conv["role"] == "assistant":
|
|
1981
|
-
yaml_config["context"] += f"你: {conv['content']}\n"
|
|
1982
|
-
yaml_config["context"] += "</history>\n"
|
|
1983
|
-
|
|
1984
|
-
yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
|
|
1269
|
+
Args:
|
|
1270
|
+
query: 代码生成查询字符串
|
|
1271
|
+
cancel_token: 可选的取消令牌
|
|
1272
|
+
"""
|
|
1273
|
+
from autocoder.common.file_handler import CodingHandler
|
|
1985
1274
|
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
f.write(yaml_content)
|
|
1275
|
+
handler = CodingHandler()
|
|
1276
|
+
handler.handle_coding_command(query, cancel_token)
|
|
1989
1277
|
|
|
1990
|
-
def execute_chat():
|
|
1991
|
-
cmd = ["--file", execute_file]
|
|
1992
|
-
auto_coder_main(cmd)
|
|
1993
|
-
result_manager = ResultManager()
|
|
1994
|
-
result_manager.append(content="", meta={"commit_message": f"auto_coder_{latest_yaml_file}","action": "coding", "input":{
|
|
1995
|
-
"query": query
|
|
1996
|
-
}})
|
|
1997
1278
|
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
print("Failed to create new YAML file.")
|
|
1279
|
+
def rules(query: str):
|
|
1280
|
+
from autocoder.chat.rules_command import handle_rules_command
|
|
2001
1281
|
|
|
2002
|
-
|
|
1282
|
+
result = handle_rules_command(query, coding_func=coding)
|
|
1283
|
+
# 只有当结果不为空时才打印,避免重复输出
|
|
1284
|
+
if result and result.strip():
|
|
1285
|
+
print(result)
|
|
2003
1286
|
completer.refresh_files()
|
|
2004
1287
|
|
|
2005
|
-
@run_in_raw_thread()
|
|
2006
|
-
def rules(query: str):
|
|
2007
|
-
from autocoder.chat.rules_command import handle_rules_command
|
|
2008
|
-
memory = get_memory()
|
|
2009
|
-
handle_rules_command(query, memory,coding_func=coding)
|
|
2010
|
-
completer.refresh_files()
|
|
2011
1288
|
|
|
2012
1289
|
@byzerllm.prompt()
|
|
2013
1290
|
def code_review(query: str) -> str:
|
|
@@ -2025,95 +1302,32 @@ def code_review(query: str) -> str:
|
|
|
2025
1302
|
如果用户的需求包含了@一个文件名 或者 @@符号, 那么重点关注这些文件或者符号(函数,类)进行上述的review。
|
|
2026
1303
|
review 过程中严格遵循上述的检查点,不要遗漏,没有发现异常的点直接跳过,只对发现的异常点,给出具体的修改后的代码。
|
|
2027
1304
|
"""
|
|
1305
|
+
return {} # type: ignore
|
|
2028
1306
|
|
|
2029
1307
|
|
|
2030
|
-
@run_in_raw_thread()
|
|
2031
1308
|
def chat(query: str):
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
yaml_config = {
|
|
2035
|
-
"include_file": ["./base/base.yml"],
|
|
2036
|
-
"include_project_structure": conf.get("include_project_structure", "true")
|
|
2037
|
-
in ["true", "True"],
|
|
2038
|
-
"human_as_model": conf.get("human_as_model", "false") == "true",
|
|
2039
|
-
"skip_build_index": conf.get("skip_build_index", "true") == "true",
|
|
2040
|
-
"skip_confirm": conf.get("skip_confirm", "true") == "true",
|
|
2041
|
-
"silence": conf.get("silence", "true") == "true",
|
|
2042
|
-
"exclude_files": memory.get("exclude_files", []),
|
|
2043
|
-
}
|
|
2044
|
-
|
|
2045
|
-
current_files = memory["current_files"]["files"] + get_llm_friendly_package_docs(
|
|
2046
|
-
return_paths=True
|
|
2047
|
-
)
|
|
2048
|
-
|
|
2049
|
-
if conf.get("enable_global_memory", "false") in ["true", "True",True]:
|
|
2050
|
-
current_files += get_global_memory_file_paths()
|
|
2051
|
-
|
|
2052
|
-
yaml_config["urls"] = current_files
|
|
2053
|
-
|
|
2054
|
-
if "emb_model" in conf:
|
|
2055
|
-
yaml_config["emb_model"] = conf["emb_model"]
|
|
2056
|
-
|
|
2057
|
-
# 解析命令
|
|
2058
|
-
commands_infos = parse_query(query)
|
|
2059
|
-
if len(commands_infos) > 0:
|
|
2060
|
-
if "query" in commands_infos:
|
|
2061
|
-
query = " ".join(commands_infos["query"]["args"])
|
|
2062
|
-
else:
|
|
2063
|
-
temp_query = ""
|
|
2064
|
-
for (command,command_info) in commands_infos.items():
|
|
2065
|
-
if command_info["args"]:
|
|
2066
|
-
temp_query = " ".join(command_info["args"])
|
|
2067
|
-
query = temp_query
|
|
2068
|
-
|
|
2069
|
-
is_new = "new" in commands_infos
|
|
2070
|
-
|
|
2071
|
-
if "learn" in commands_infos:
|
|
2072
|
-
commands_infos["no_context"] = {}
|
|
2073
|
-
|
|
2074
|
-
if "review" in commands_infos:
|
|
2075
|
-
commands_infos["no_context"] = {}
|
|
2076
|
-
|
|
2077
|
-
yaml_config["action"] = commands_infos
|
|
2078
|
-
|
|
2079
|
-
for key, value in conf.items():
|
|
2080
|
-
converted_value = convert_config_value(key, value)
|
|
2081
|
-
if converted_value is not None:
|
|
2082
|
-
yaml_config[key] = converted_value
|
|
2083
|
-
|
|
2084
|
-
query = Image.convert_image_paths_from(query)
|
|
2085
|
-
|
|
2086
|
-
yaml_config["query"] = query
|
|
2087
|
-
|
|
2088
|
-
yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
|
|
2089
|
-
|
|
2090
|
-
execute_file = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
2091
|
-
|
|
2092
|
-
with open(os.path.join(execute_file), "w",encoding="utf-8") as f:
|
|
2093
|
-
f.write(yaml_content)
|
|
1309
|
+
"""
|
|
1310
|
+
处理聊天命令,使用 ChatHandler 进行统一处理
|
|
2094
1311
|
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
auto_coder_main(cmd)
|
|
1312
|
+
Args:
|
|
1313
|
+
query: 聊天查询字符串
|
|
1314
|
+
"""
|
|
1315
|
+
from autocoder.common.file_handler import ChatHandler
|
|
2100
1316
|
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
finally:
|
|
2104
|
-
os.remove(execute_file)
|
|
1317
|
+
handler = ChatHandler()
|
|
1318
|
+
handler.handle_chat_command(query)
|
|
2105
1319
|
|
|
2106
1320
|
|
|
2107
|
-
@run_in_raw_thread()
|
|
2108
1321
|
def summon(query: str):
|
|
1322
|
+
memory = get_current_memory()
|
|
2109
1323
|
conf = memory.get("conf", {})
|
|
2110
|
-
current_files =
|
|
1324
|
+
current_files = get_current_files()
|
|
2111
1325
|
|
|
2112
1326
|
file_contents = []
|
|
2113
1327
|
for file in current_files:
|
|
2114
1328
|
if os.path.exists(file):
|
|
2115
1329
|
try:
|
|
2116
|
-
with open(file, "r",encoding="utf-8") as f:
|
|
1330
|
+
with open(file, "r", encoding="utf-8") as f:
|
|
2117
1331
|
content = f.read()
|
|
2118
1332
|
s = f"##File: {file}\n{content}\n\n"
|
|
2119
1333
|
file_contents.append(s)
|
|
@@ -2149,7 +1363,7 @@ def summon(query: str):
|
|
|
2149
1363
|
|
|
2150
1364
|
execute_file = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
2151
1365
|
|
|
2152
|
-
with open(os.path.join(execute_file), "w",encoding="utf-8") as f:
|
|
1366
|
+
with open(os.path.join(execute_file), "w", encoding="utf-8") as f:
|
|
2153
1367
|
f.write(yaml_content)
|
|
2154
1368
|
|
|
2155
1369
|
def execute_summon():
|
|
@@ -2161,9 +1375,8 @@ def summon(query: str):
|
|
|
2161
1375
|
os.remove(execute_file)
|
|
2162
1376
|
|
|
2163
1377
|
|
|
2164
|
-
@run_in_raw_thread()
|
|
2165
1378
|
def design(query: str):
|
|
2166
|
-
|
|
1379
|
+
memory = get_current_memory()
|
|
2167
1380
|
conf = memory.get("conf", {})
|
|
2168
1381
|
yaml_config = {
|
|
2169
1382
|
"include_file": ["./base/base.yml"],
|
|
@@ -2196,7 +1409,7 @@ def design(query: str):
|
|
|
2196
1409
|
|
|
2197
1410
|
execute_file = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
2198
1411
|
|
|
2199
|
-
with open(os.path.join(execute_file), "w",encoding="utf-8") as f:
|
|
1412
|
+
with open(os.path.join(execute_file), "w", encoding="utf-8") as f:
|
|
2200
1413
|
f.write(yaml_content)
|
|
2201
1414
|
|
|
2202
1415
|
def execute_design():
|
|
@@ -2208,117 +1421,21 @@ def design(query: str):
|
|
|
2208
1421
|
os.remove(execute_file)
|
|
2209
1422
|
|
|
2210
1423
|
|
|
2211
|
-
@run_in_raw_thread()
|
|
2212
1424
|
def active_context(query: str):
|
|
2213
1425
|
"""
|
|
2214
|
-
|
|
2215
|
-
|
|
1426
|
+
处理活动上下文命令,使用 ActiveContextHandler 进行统一处理
|
|
1427
|
+
|
|
2216
1428
|
Args:
|
|
2217
1429
|
query: 命令参数,例如 "list" 列出所有任务
|
|
2218
|
-
"""
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
if len(commands_infos) > 0:
|
|
2224
|
-
if "list" in commands_infos:
|
|
2225
|
-
command = "list"
|
|
2226
|
-
if "run" in commands_infos:
|
|
2227
|
-
command = "run"
|
|
2228
|
-
|
|
2229
|
-
args = get_final_config()
|
|
2230
|
-
printer = Printer()
|
|
2231
|
-
# 获取LLM实例
|
|
2232
|
-
llm = get_single_llm(args.model,product_mode=args.product_mode)
|
|
2233
|
-
action_file_manager = ActionYmlFileManager(args.source_dir)
|
|
2234
|
-
|
|
2235
|
-
# 获取配置和参数
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
active_context_manager = ActiveContextManager(llm, args.source_dir)
|
|
2239
|
-
if command == "run":
|
|
2240
|
-
file_name = commands_infos["run"]["args"][-1]
|
|
2241
|
-
args.file = action_file_manager.get_full_path_by_file_name(file_name)
|
|
2242
|
-
## 因为更新了args.file
|
|
2243
|
-
active_context_manager = ActiveContextManager(llm, args.source_dir)
|
|
2244
|
-
task_id = active_context_manager.process_changes(args)
|
|
2245
|
-
printer.print_in_terminal("active_context_background_task",
|
|
2246
|
-
style="blue",
|
|
2247
|
-
task_id=task_id)
|
|
2248
|
-
|
|
2249
|
-
# 处理不同的命令
|
|
2250
|
-
if command == "list":
|
|
2251
|
-
# 获取所有任务
|
|
2252
|
-
all_tasks = active_context_manager.get_all_tasks()
|
|
2253
|
-
|
|
2254
|
-
if not all_tasks:
|
|
2255
|
-
console = Console()
|
|
2256
|
-
console.print("[yellow]没有找到任何活动上下文任务[/yellow]")
|
|
2257
|
-
return
|
|
2258
|
-
|
|
2259
|
-
# 创建表格
|
|
2260
|
-
table = Table(title="活动上下文任务列表", show_lines=True, expand=True)
|
|
2261
|
-
table.add_column("任务ID", style="cyan", no_wrap=False)
|
|
2262
|
-
table.add_column("状态", style="green", no_wrap=False)
|
|
2263
|
-
table.add_column("开始时间", style="yellow", no_wrap=False)
|
|
2264
|
-
table.add_column("完成时间", style="yellow", no_wrap=False)
|
|
2265
|
-
table.add_column("文件", style="blue", no_wrap=False)
|
|
2266
|
-
table.add_column("Token统计", style="magenta", no_wrap=False)
|
|
2267
|
-
table.add_column("费用", style="red", no_wrap=False)
|
|
2268
|
-
|
|
2269
|
-
# 添加任务数据
|
|
2270
|
-
for task in all_tasks:
|
|
2271
|
-
status = task.get("status", "未知")
|
|
2272
|
-
status_display = status
|
|
2273
|
-
|
|
2274
|
-
# 根据状态设置不同的显示样式
|
|
2275
|
-
if status == "completed":
|
|
2276
|
-
status_display = "[green]已完成[/green]"
|
|
2277
|
-
elif status == "running":
|
|
2278
|
-
status_display = "[blue]运行中[/blue]"
|
|
2279
|
-
elif status == "queued":
|
|
2280
|
-
position = task.get("queue_position", 0)
|
|
2281
|
-
status_display = f"[yellow]排队中 (位置: {position})[/yellow]"
|
|
2282
|
-
elif status == "failed":
|
|
2283
|
-
status_display = "[red]失败[/red]"
|
|
2284
|
-
|
|
2285
|
-
# 格式化时间
|
|
2286
|
-
start_time = task.get("start_time", "")
|
|
2287
|
-
start_time_str = start_time.strftime("%Y-%m-%d %H:%M:%S") if start_time else "未知"
|
|
2288
|
-
|
|
2289
|
-
completion_time = task.get("completion_time", "")
|
|
2290
|
-
completion_time_str = completion_time.strftime("%Y-%m-%d %H:%M:%S") if completion_time else "-"
|
|
2291
|
-
|
|
2292
|
-
# 获取文件名
|
|
2293
|
-
file_name = task.get("file_name", "未知")
|
|
2294
|
-
|
|
2295
|
-
# 获取token信息
|
|
2296
|
-
total_tokens = task.get("total_tokens", 0)
|
|
2297
|
-
input_tokens = task.get("input_tokens", 0)
|
|
2298
|
-
output_tokens = task.get("output_tokens", 0)
|
|
2299
|
-
token_info = f"总计: {total_tokens:,}\n输入: {input_tokens:,}\n输出: {output_tokens:,}"
|
|
2300
|
-
|
|
2301
|
-
# 获取费用信息
|
|
2302
|
-
cost = task.get("cost", 0.0)
|
|
2303
|
-
cost_info = f"${cost:.6f}"
|
|
2304
|
-
|
|
2305
|
-
# 添加到表格
|
|
2306
|
-
table.add_row(
|
|
2307
|
-
task.get("task_id", "未知"),
|
|
2308
|
-
status_display,
|
|
2309
|
-
start_time_str,
|
|
2310
|
-
completion_time_str,
|
|
2311
|
-
file_name,
|
|
2312
|
-
token_info,
|
|
2313
|
-
cost_info
|
|
2314
|
-
)
|
|
2315
|
-
|
|
2316
|
-
# 显示表格
|
|
2317
|
-
console = Console(width=120) # 设置更宽的显示宽度
|
|
2318
|
-
console.print(table)
|
|
1430
|
+
"""
|
|
1431
|
+
from autocoder.common.file_handler import ActiveContextHandler
|
|
1432
|
+
|
|
1433
|
+
handler = ActiveContextHandler()
|
|
1434
|
+
handler.handle_active_context_command(query)
|
|
2319
1435
|
|
|
2320
1436
|
|
|
2321
1437
|
def voice_input():
|
|
1438
|
+
memory = get_current_memory()
|
|
2322
1439
|
conf = memory.get("conf", {})
|
|
2323
1440
|
yaml_config = {
|
|
2324
1441
|
"include_file": ["./base/base.yml"],
|
|
@@ -2335,7 +1452,7 @@ def voice_input():
|
|
|
2335
1452
|
|
|
2336
1453
|
execute_file = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
2337
1454
|
|
|
2338
|
-
with open(os.path.join(execute_file), "w",encoding="utf-8") as f:
|
|
1455
|
+
with open(os.path.join(execute_file), "w", encoding="utf-8") as f:
|
|
2339
1456
|
f.write(yaml_content)
|
|
2340
1457
|
|
|
2341
1458
|
def execute_voice2text_command():
|
|
@@ -2343,14 +1460,16 @@ def voice_input():
|
|
|
2343
1460
|
|
|
2344
1461
|
try:
|
|
2345
1462
|
execute_voice2text_command()
|
|
2346
|
-
with open(
|
|
1463
|
+
with open(
|
|
1464
|
+
os.path.join(".auto-coder", "exchange.txt"), "r", encoding="utf-8"
|
|
1465
|
+
) as f:
|
|
2347
1466
|
return f.read()
|
|
2348
1467
|
finally:
|
|
2349
1468
|
os.remove(execute_file)
|
|
2350
1469
|
|
|
2351
1470
|
|
|
2352
|
-
@run_in_raw_thread()
|
|
2353
1471
|
def generate_shell_command(input_text):
|
|
1472
|
+
memory = get_current_memory()
|
|
2354
1473
|
conf = memory.get("conf", {})
|
|
2355
1474
|
yaml_config = {
|
|
2356
1475
|
"include_file": ["./base/base.yml"],
|
|
@@ -2365,428 +1484,58 @@ def generate_shell_command(input_text):
|
|
|
2365
1484
|
|
|
2366
1485
|
execute_file = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
2367
1486
|
|
|
2368
|
-
with open(os.path.join(execute_file), "w",encoding="utf-8") as f:
|
|
1487
|
+
with open(os.path.join(execute_file), "w", encoding="utf-8") as f:
|
|
2369
1488
|
f.write(yaml_content)
|
|
2370
1489
|
|
|
2371
1490
|
try:
|
|
2372
1491
|
auto_coder_main(["agent", "generate_command", "--file", execute_file])
|
|
2373
|
-
with open(
|
|
1492
|
+
with open(
|
|
1493
|
+
os.path.join(".auto-coder", "exchange.txt"), "r", encoding="utf-8"
|
|
1494
|
+
) as f:
|
|
2374
1495
|
shell_script = f.read()
|
|
2375
1496
|
result_manager = ResultManager()
|
|
2376
|
-
result_manager.add_result(
|
|
2377
|
-
|
|
2378
|
-
"input": {
|
|
2379
|
-
|
|
2380
|
-
}
|
|
2381
|
-
})
|
|
1497
|
+
result_manager.add_result(
|
|
1498
|
+
content=shell_script,
|
|
1499
|
+
meta={"action": "generate_shell_command", "input": {"query": input_text}},
|
|
1500
|
+
)
|
|
2382
1501
|
return shell_script
|
|
2383
1502
|
finally:
|
|
2384
1503
|
os.remove(execute_file)
|
|
2385
1504
|
|
|
1505
|
+
|
|
2386
1506
|
def manage_models(query: str):
|
|
2387
|
-
"""
|
|
2388
|
-
Handle /models subcommands:
|
|
2389
|
-
/models /list - List all models (default + custom)
|
|
2390
|
-
/models /add <name> <api_key> - Add model with simplified params
|
|
2391
|
-
/models /add_model name=xxx base_url=xxx ... - Add model with custom params
|
|
2392
|
-
/models /remove <name> - Remove model by name
|
|
2393
1507
|
"""
|
|
2394
|
-
|
|
2395
|
-
printer = Printer(console=console)
|
|
2396
|
-
|
|
2397
|
-
product_mode = memory.get("product_mode", "lite")
|
|
2398
|
-
if product_mode != "lite":
|
|
2399
|
-
printer.print_in_terminal("models_lite_only", style="red")
|
|
2400
|
-
return
|
|
2401
|
-
|
|
2402
|
-
models_data = models_module.load_models()
|
|
2403
|
-
subcmd = ""
|
|
2404
|
-
if "/list" in query:
|
|
2405
|
-
subcmd = "/list"
|
|
2406
|
-
query = query.replace("/list", "", 1).strip()
|
|
2407
|
-
|
|
2408
|
-
if "/add_model" in query:
|
|
2409
|
-
subcmd = "/add_model"
|
|
2410
|
-
query = query.replace("/add_model", "", 1).strip()
|
|
2411
|
-
|
|
2412
|
-
if "/add" in query:
|
|
2413
|
-
subcmd = "/add"
|
|
2414
|
-
query = query.replace("/add", "", 1).strip()
|
|
2415
|
-
|
|
2416
|
-
# alias to /add
|
|
2417
|
-
if "/activate" in query:
|
|
2418
|
-
subcmd = "/add"
|
|
2419
|
-
query = query.replace("/activate", "", 1).strip()
|
|
2420
|
-
|
|
2421
|
-
if "/remove" in query:
|
|
2422
|
-
subcmd = "/remove"
|
|
2423
|
-
query = query.replace("/remove", "", 1).strip()
|
|
2424
|
-
|
|
2425
|
-
if "/speed-test" in query:
|
|
2426
|
-
subcmd = "/speed-test"
|
|
2427
|
-
query = query.replace("/speed-test", "", 1).strip()
|
|
2428
|
-
|
|
2429
|
-
if "/speed_test" in query:
|
|
2430
|
-
subcmd = "/speed-test"
|
|
2431
|
-
query = query.replace("/speed_test", "", 1).strip()
|
|
2432
|
-
|
|
2433
|
-
if "input_price" in query:
|
|
2434
|
-
subcmd = "/input_price"
|
|
2435
|
-
query = query.replace("/input_price", "", 1).strip()
|
|
2436
|
-
|
|
2437
|
-
if "output_price" in query:
|
|
2438
|
-
subcmd = "/output_price"
|
|
2439
|
-
query = query.replace("/output_price", "", 1).strip()
|
|
2440
|
-
|
|
2441
|
-
if "/speed" in query:
|
|
2442
|
-
subcmd = "/speed"
|
|
2443
|
-
query = query.replace("/speed", "", 1).strip()
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
if not subcmd:
|
|
2448
|
-
printer.print_in_terminal("models_usage")
|
|
2449
|
-
|
|
2450
|
-
result_manager = ResultManager()
|
|
2451
|
-
if subcmd == "/list":
|
|
2452
|
-
if models_data:
|
|
2453
|
-
# Sort models by speed (average_speed)
|
|
2454
|
-
sorted_models = sorted(models_data, key=lambda x: float(x.get('average_speed', 0)))
|
|
2455
|
-
sorted_models.reverse()
|
|
2456
|
-
|
|
2457
|
-
table = Table(
|
|
2458
|
-
title=printer.get_message_from_key("models_title"),
|
|
2459
|
-
expand=True,
|
|
2460
|
-
show_lines=True
|
|
2461
|
-
)
|
|
2462
|
-
table.add_column("Name", style="cyan", width=30, overflow="fold", no_wrap=False)
|
|
2463
|
-
table.add_column("Model Name", style="magenta", width=30, overflow="fold", no_wrap=False)
|
|
2464
|
-
table.add_column("Base URL", style="white", width=40, overflow="fold", no_wrap=False)
|
|
2465
|
-
table.add_column("Input Price (M)", style="magenta", width=15, overflow="fold", no_wrap=False)
|
|
2466
|
-
table.add_column("Output Price (M)", style="magenta", width=15, overflow="fold", no_wrap=False)
|
|
2467
|
-
table.add_column("Speed (s/req)", style="blue", width=15, overflow="fold", no_wrap=False)
|
|
2468
|
-
for m in sorted_models:
|
|
2469
|
-
# Check if api_key_path exists and file exists
|
|
2470
|
-
is_api_key_set = "api_key" in m
|
|
2471
|
-
name = m.get("name", "")
|
|
2472
|
-
if is_api_key_set:
|
|
2473
|
-
api_key = m.get("api_key", "").strip()
|
|
2474
|
-
if not api_key:
|
|
2475
|
-
printer.print_in_terminal("models_api_key_empty", style="yellow", name=name)
|
|
2476
|
-
name = f"{name} *"
|
|
2477
|
-
|
|
2478
|
-
table.add_row(
|
|
2479
|
-
name,
|
|
2480
|
-
m.get("model_name", ""),
|
|
2481
|
-
m.get("base_url", ""),
|
|
2482
|
-
f"{m.get('input_price', 0.0):.2f}",
|
|
2483
|
-
f"{m.get('output_price', 0.0):.2f}",
|
|
2484
|
-
f"{m.get('average_speed', 0.0):.3f}"
|
|
2485
|
-
)
|
|
2486
|
-
console.print(table)
|
|
2487
|
-
result_manager.add_result(content=json.dumps(sorted_models,ensure_ascii=False),meta={
|
|
2488
|
-
"action": "models",
|
|
2489
|
-
"input": {
|
|
2490
|
-
"query": query
|
|
2491
|
-
}
|
|
2492
|
-
})
|
|
2493
|
-
|
|
2494
|
-
else:
|
|
2495
|
-
printer.print_in_terminal("models_no_models", style="yellow")
|
|
2496
|
-
result_manager.add_result(content="No models found",meta={
|
|
2497
|
-
"action": "models",
|
|
2498
|
-
"input": {
|
|
2499
|
-
"query": query
|
|
2500
|
-
}
|
|
2501
|
-
})
|
|
2502
|
-
|
|
2503
|
-
elif subcmd == "/input_price":
|
|
2504
|
-
args = query.strip().split()
|
|
2505
|
-
if len(args) >= 2:
|
|
2506
|
-
name = args[0]
|
|
2507
|
-
try:
|
|
2508
|
-
price = float(args[1])
|
|
2509
|
-
if models_module.update_model_input_price(name, price):
|
|
2510
|
-
printer.print_in_terminal("models_input_price_updated", style="green", name=name, price=price)
|
|
2511
|
-
result_manager.add_result(content=f"models_input_price_updated: {name} {price}",meta={
|
|
2512
|
-
"action": "models",
|
|
2513
|
-
"input": {
|
|
2514
|
-
"query": query
|
|
2515
|
-
}
|
|
2516
|
-
})
|
|
2517
|
-
else:
|
|
2518
|
-
printer.print_in_terminal("models_not_found", style="red", name=name)
|
|
2519
|
-
result_manager.add_result(content=f"models_not_found: {name}",meta={
|
|
2520
|
-
"action": "models",
|
|
2521
|
-
"input": {
|
|
2522
|
-
"query": query
|
|
2523
|
-
}
|
|
2524
|
-
})
|
|
2525
|
-
except ValueError as e:
|
|
2526
|
-
result_manager.add_result(content=f"models_invalid_price: {str(e)}",meta={
|
|
2527
|
-
"action": "models",
|
|
2528
|
-
"input": {
|
|
2529
|
-
"query": query
|
|
2530
|
-
}
|
|
2531
|
-
})
|
|
2532
|
-
printer.print_in_terminal("models_invalid_price", style="red", error=str(e))
|
|
2533
|
-
else:
|
|
2534
|
-
result_manager.add_result(content=printer.get_message_from_key("models_input_price_usage"),meta={
|
|
2535
|
-
"action": "models",
|
|
2536
|
-
"input": {
|
|
2537
|
-
"query": query
|
|
2538
|
-
}
|
|
2539
|
-
})
|
|
2540
|
-
printer.print_in_terminal("models_input_price_usage", style="red")
|
|
2541
|
-
|
|
2542
|
-
elif subcmd == "/output_price":
|
|
2543
|
-
args = query.strip().split()
|
|
2544
|
-
if len(args) >= 2:
|
|
2545
|
-
name = args[0]
|
|
2546
|
-
try:
|
|
2547
|
-
price = float(args[1])
|
|
2548
|
-
if models_module.update_model_output_price(name, price):
|
|
2549
|
-
printer.print_in_terminal("models_output_price_updated", style="green", name=name, price=price)
|
|
2550
|
-
result_manager.add_result(content=f"models_output_price_updated: {name} {price}",meta={
|
|
2551
|
-
"action": "models",
|
|
2552
|
-
"input": {
|
|
2553
|
-
"query": query
|
|
2554
|
-
}
|
|
2555
|
-
})
|
|
2556
|
-
else:
|
|
2557
|
-
printer.print_in_terminal("models_not_found", style="red", name=name)
|
|
2558
|
-
result_manager.add_result(content=f"models_not_found: {name}",meta={
|
|
2559
|
-
"action": "models",
|
|
2560
|
-
"input": {
|
|
2561
|
-
"query": query
|
|
2562
|
-
}
|
|
2563
|
-
})
|
|
2564
|
-
except ValueError as e:
|
|
2565
|
-
printer.print_in_terminal("models_invalid_price", style="red", error=str(e))
|
|
2566
|
-
result_manager.add_result(content=f"models_invalid_price: {str(e)}",meta={
|
|
2567
|
-
"action": "models",
|
|
2568
|
-
"input": {
|
|
2569
|
-
"query": query
|
|
2570
|
-
}
|
|
2571
|
-
})
|
|
2572
|
-
else:
|
|
2573
|
-
result_manager.add_result(content=printer.get_message_from_key("models_output_price_usage"),meta={
|
|
2574
|
-
"action": "models",
|
|
2575
|
-
"input": {
|
|
2576
|
-
"query": query
|
|
2577
|
-
}
|
|
2578
|
-
})
|
|
2579
|
-
printer.print_in_terminal("models_output_price_usage", style="red")
|
|
2580
|
-
|
|
2581
|
-
elif subcmd == "/speed":
|
|
2582
|
-
args = query.strip().split()
|
|
2583
|
-
if len(args) >= 2:
|
|
2584
|
-
name = args[0]
|
|
2585
|
-
try:
|
|
2586
|
-
speed = float(args[1])
|
|
2587
|
-
if models_module.update_model_speed(name, speed):
|
|
2588
|
-
printer.print_in_terminal("models_speed_updated", style="green", name=name, speed=speed)
|
|
2589
|
-
result_manager.add_result(content=f"models_speed_updated: {name} {speed}",meta={
|
|
2590
|
-
"action": "models",
|
|
2591
|
-
"input": {
|
|
2592
|
-
"query": query
|
|
2593
|
-
}
|
|
2594
|
-
})
|
|
2595
|
-
else:
|
|
2596
|
-
printer.print_in_terminal("models_not_found", style="red", name=name)
|
|
2597
|
-
result_manager.add_result(content=f"models_not_found: {name}",meta={
|
|
2598
|
-
"action": "models",
|
|
2599
|
-
"input": {
|
|
2600
|
-
"query": query
|
|
2601
|
-
}
|
|
2602
|
-
})
|
|
2603
|
-
except ValueError as e:
|
|
2604
|
-
printer.print_in_terminal("models_invalid_speed", style="red", error=str(e))
|
|
2605
|
-
result_manager.add_result(content=f"models_invalid_speed: {str(e)}",meta={
|
|
2606
|
-
"action": "models",
|
|
2607
|
-
"input": {
|
|
2608
|
-
"query": query
|
|
2609
|
-
}
|
|
2610
|
-
})
|
|
2611
|
-
else:
|
|
2612
|
-
result_manager.add_result(content=printer.get_message_from_key("models_speed_usage"),meta={
|
|
2613
|
-
"action": "models",
|
|
2614
|
-
"input": {
|
|
2615
|
-
"query": query
|
|
2616
|
-
}
|
|
2617
|
-
})
|
|
2618
|
-
printer.print_in_terminal("models_speed_usage", style="red")
|
|
2619
|
-
|
|
2620
|
-
elif subcmd == "/speed-test":
|
|
2621
|
-
from autocoder.common.model_speed_tester import render_speed_test_in_terminal
|
|
2622
|
-
test_rounds = 1 # 默认测试轮数
|
|
2623
|
-
|
|
2624
|
-
enable_long_context = False
|
|
2625
|
-
if "/long_context" in query:
|
|
2626
|
-
enable_long_context = True
|
|
2627
|
-
query = query.replace("/long_context", "", 1).strip()
|
|
2628
|
-
|
|
2629
|
-
if "/long-context" in query:
|
|
2630
|
-
enable_long_context = True
|
|
2631
|
-
query = query.replace("/long-context", "", 1).strip()
|
|
2632
|
-
|
|
2633
|
-
# 解析可选的测试轮数参数
|
|
2634
|
-
args = query.strip().split()
|
|
2635
|
-
if args and args[0].isdigit():
|
|
2636
|
-
test_rounds = int(args[0])
|
|
2637
|
-
|
|
2638
|
-
render_speed_test_in_terminal(product_mode, test_rounds,enable_long_context=enable_long_context)
|
|
2639
|
-
## 等待优化,获取明细数据
|
|
2640
|
-
result_manager.add_result(content="models test success",meta={
|
|
2641
|
-
"action": "models",
|
|
2642
|
-
"input": {
|
|
2643
|
-
"query": query
|
|
2644
|
-
}
|
|
2645
|
-
})
|
|
2646
|
-
|
|
2647
|
-
elif subcmd == "/add":
|
|
2648
|
-
# Support both simplified and legacy formats
|
|
2649
|
-
args = query.strip().split(" ")
|
|
2650
|
-
if len(args) == 2:
|
|
2651
|
-
# Simplified: /models /add <name> <api_key>
|
|
2652
|
-
name, api_key = args[0], args[1]
|
|
2653
|
-
result = models_module.update_model_with_api_key(name, api_key)
|
|
2654
|
-
if result:
|
|
2655
|
-
result_manager.add_result(content=f"models_added: {name}",meta={
|
|
2656
|
-
"action": "models",
|
|
2657
|
-
"input": {
|
|
2658
|
-
"query": query
|
|
2659
|
-
}
|
|
2660
|
-
})
|
|
2661
|
-
printer.print_in_terminal("models_added", style="green", name=name)
|
|
2662
|
-
else:
|
|
2663
|
-
result_manager.add_result(content=f"models_add_failed: {name}",meta={
|
|
2664
|
-
"action": "models",
|
|
2665
|
-
"input": {
|
|
2666
|
-
"query": query
|
|
2667
|
-
}
|
|
2668
|
-
})
|
|
2669
|
-
printer.print_in_terminal("models_add_failed", style="red", name=name)
|
|
2670
|
-
else:
|
|
2671
|
-
models_list = "\n".join([m["name"] for m in models_module.default_models_list])
|
|
2672
|
-
printer.print_in_terminal("models_add_usage", style="red", models=models_list)
|
|
2673
|
-
result_manager.add_result(content=printer.get_message_from_key_with_format("models_add_usage",models=models_list),meta={
|
|
2674
|
-
"action": "models",
|
|
2675
|
-
"input": {
|
|
2676
|
-
"query": query
|
|
2677
|
-
}
|
|
2678
|
-
})
|
|
2679
|
-
|
|
2680
|
-
elif subcmd == "/add_model":
|
|
2681
|
-
# Parse key=value pairs: /models /add_model name=abc base_url=http://xx ...
|
|
2682
|
-
# Collect key=value pairs
|
|
2683
|
-
kv_pairs = shlex.split(query)
|
|
2684
|
-
data_dict = {}
|
|
2685
|
-
for pair in kv_pairs:
|
|
2686
|
-
if '=' not in pair:
|
|
2687
|
-
printer.print_in_terminal("models_add_model_params", style="red")
|
|
2688
|
-
continue
|
|
2689
|
-
k, v = pair.split('=', 1)
|
|
2690
|
-
data_dict[k.strip()] = v.strip()
|
|
2691
|
-
|
|
2692
|
-
# Name is required
|
|
2693
|
-
if "name" not in data_dict:
|
|
2694
|
-
printer.print_in_terminal("models_add_model_name_required", style="red")
|
|
2695
|
-
return
|
|
1508
|
+
处理模型管理命令,使用 ModelsHandler 进行统一处理
|
|
2696
1509
|
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
"action": "models",
|
|
2702
|
-
"input": {
|
|
2703
|
-
"query": query
|
|
2704
|
-
}
|
|
2705
|
-
})
|
|
2706
|
-
return
|
|
1510
|
+
Args:
|
|
1511
|
+
query: 查询字符串,支持多种模型管理子命令
|
|
1512
|
+
"""
|
|
1513
|
+
from autocoder.common.file_handler import ModelsHandler
|
|
2707
1514
|
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
"name": data_dict["name"],
|
|
2711
|
-
"model_type": data_dict.get("model_type", "saas/openai"),
|
|
2712
|
-
"model_name": data_dict.get("model_name", data_dict["name"]),
|
|
2713
|
-
"base_url": data_dict.get("base_url", "https://api.openai.com/v1"),
|
|
2714
|
-
"api_key_path": data_dict.get("api_key_path", "api.openai.com"),
|
|
2715
|
-
"description": data_dict.get("description", ""),
|
|
2716
|
-
"is_reasoning": data_dict.get("is_reasoning", "false") in ["true", "True", "TRUE", "1"]
|
|
2717
|
-
}
|
|
1515
|
+
handler = ModelsHandler()
|
|
1516
|
+
handler.handle_models_command(query)
|
|
2718
1517
|
|
|
2719
|
-
models_data.append(final_model)
|
|
2720
|
-
models_module.save_models(models_data)
|
|
2721
|
-
printer.print_in_terminal("models_add_model_success", style="green", name=data_dict["name"])
|
|
2722
|
-
result_manager.add_result(content=f"models_add_model_success: {data_dict['name']}",meta={
|
|
2723
|
-
"action": "models",
|
|
2724
|
-
"input": {
|
|
2725
|
-
"query": query
|
|
2726
|
-
}
|
|
2727
|
-
})
|
|
2728
|
-
|
|
2729
|
-
elif subcmd == "/remove":
|
|
2730
|
-
args = query.strip().split(" ")
|
|
2731
|
-
if len(args) < 1:
|
|
2732
|
-
printer.print_in_terminal("models_add_usage", style="red")
|
|
2733
|
-
result_manager.add_result(content=printer.get_message_from_key("models_add_usage"),meta={
|
|
2734
|
-
"action": "models",
|
|
2735
|
-
"input": {
|
|
2736
|
-
"query": query
|
|
2737
|
-
}
|
|
2738
|
-
})
|
|
2739
|
-
return
|
|
2740
|
-
name = args[0]
|
|
2741
|
-
filtered_models = [m for m in models_data if m["name"] != name]
|
|
2742
|
-
if len(filtered_models) == len(models_data):
|
|
2743
|
-
printer.print_in_terminal("models_add_model_remove", style="yellow", name=name)
|
|
2744
|
-
result_manager.add_result(content=printer.get_message_from_key_with_format("models_add_model_remove",name=name),meta={
|
|
2745
|
-
"action": "models",
|
|
2746
|
-
"input": {
|
|
2747
|
-
"query": query
|
|
2748
|
-
}
|
|
2749
|
-
})
|
|
2750
|
-
return
|
|
2751
|
-
models_module.save_models(filtered_models)
|
|
2752
|
-
printer.print_in_terminal("models_add_model_removed", style="green", name=name)
|
|
2753
|
-
result_manager.add_result(content=printer.get_message_from_key_with_format("models_add_model_removed",name=name),meta={
|
|
2754
|
-
"action": "models",
|
|
2755
|
-
"input": {
|
|
2756
|
-
"query": query
|
|
2757
|
-
}
|
|
2758
|
-
})
|
|
2759
|
-
else:
|
|
2760
|
-
printer.print_in_terminal("models_unknown_subcmd", style="yellow", subcmd=subcmd)
|
|
2761
|
-
result_manager.add_result(content=printer.get_message_from_key_with_format("models_unknown_subcmd",subcmd=subcmd),meta={
|
|
2762
|
-
"action": "models",
|
|
2763
|
-
"input": {
|
|
2764
|
-
"query": query
|
|
2765
|
-
}
|
|
2766
|
-
})
|
|
2767
1518
|
|
|
2768
1519
|
def exclude_dirs(dir_names: List[str]):
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
if "exclude_dirs" not in memory:
|
|
2776
|
-
memory["exclude_dirs"] = existing_dirs
|
|
2777
|
-
print(f"Added exclude dirs: {dirs_to_add}")
|
|
2778
|
-
exclude_files([f"regex://.*/{d}/*." for d in dirs_to_add])
|
|
1520
|
+
memory_manager = get_memory_manager()
|
|
1521
|
+
new_dirs = memory_manager.add_exclude_dirs(dir_names)
|
|
1522
|
+
|
|
1523
|
+
if new_dirs:
|
|
1524
|
+
print(f"Added exclude dirs: {new_dirs}")
|
|
1525
|
+
exclude_files(",".join([f"regex://.*/{d}/*." for d in new_dirs]))
|
|
2779
1526
|
else:
|
|
2780
1527
|
print("All specified dirs are already in the exclude list.")
|
|
2781
|
-
save_memory()
|
|
2782
1528
|
completer.refresh_files()
|
|
2783
1529
|
|
|
1530
|
+
|
|
2784
1531
|
def exclude_files(query: str):
|
|
1532
|
+
memory_manager = get_memory_manager()
|
|
2785
1533
|
result_manager = ResultManager()
|
|
2786
1534
|
printer = Printer()
|
|
1535
|
+
|
|
2787
1536
|
if "/list" in query:
|
|
2788
1537
|
query = query.replace("/list", "", 1).strip()
|
|
2789
|
-
existing_file_patterns =
|
|
1538
|
+
existing_file_patterns = memory_manager.get_exclude_files()
|
|
2790
1539
|
console = Console()
|
|
2791
1540
|
# 打印表格
|
|
2792
1541
|
table = Table(title="Exclude Files")
|
|
@@ -2794,70 +1543,58 @@ def exclude_files(query: str):
|
|
|
2794
1543
|
for file_pattern in existing_file_patterns:
|
|
2795
1544
|
table.add_row(file_pattern)
|
|
2796
1545
|
console.print(table)
|
|
2797
|
-
result_manager.add_result(
|
|
2798
|
-
"
|
|
2799
|
-
"input": {
|
|
2800
|
-
|
|
2801
|
-
}
|
|
2802
|
-
})
|
|
1546
|
+
result_manager.add_result(
|
|
1547
|
+
content=f"Exclude files: {existing_file_patterns}",
|
|
1548
|
+
meta={"action": "exclude_files", "input": {"query": query}},
|
|
1549
|
+
)
|
|
2803
1550
|
return
|
|
2804
1551
|
|
|
2805
1552
|
if "/drop" in query:
|
|
2806
1553
|
query = query.replace("/drop", "", 1).strip()
|
|
2807
|
-
|
|
2808
|
-
existing_file_patterns.remove(query.strip())
|
|
2809
|
-
memory["exclude_files"] = existing_file_patterns
|
|
2810
|
-
save_memory()
|
|
1554
|
+
removed_patterns = memory_manager.remove_exclude_files([query.strip()])
|
|
2811
1555
|
completer.refresh_files()
|
|
2812
|
-
result_manager.add_result(
|
|
2813
|
-
"
|
|
2814
|
-
"input": {
|
|
2815
|
-
|
|
2816
|
-
}
|
|
2817
|
-
})
|
|
1556
|
+
result_manager.add_result(
|
|
1557
|
+
content=f"Dropped exclude files: {removed_patterns}",
|
|
1558
|
+
meta={"action": "exclude_files", "input": {"query": query}},
|
|
1559
|
+
)
|
|
2818
1560
|
return
|
|
2819
|
-
|
|
1561
|
+
|
|
2820
1562
|
new_file_patterns = query.strip().split(",")
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
"input": {
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
"
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
})
|
|
2846
|
-
save_memory()
|
|
2847
|
-
print(f"Added exclude files: {file_patterns_to_add}")
|
|
1563
|
+
|
|
1564
|
+
# Validate patterns
|
|
1565
|
+
for file_pattern in new_file_patterns:
|
|
1566
|
+
if not file_pattern.startswith("regex://"):
|
|
1567
|
+
result_manager.add_result(
|
|
1568
|
+
content=printer.get_message_from_key_with_format(
|
|
1569
|
+
"invalid_file_pattern", file_pattern=file_pattern
|
|
1570
|
+
),
|
|
1571
|
+
meta={"action": "exclude_files", "input": {"query": file_pattern}},
|
|
1572
|
+
)
|
|
1573
|
+
raise ValueError(
|
|
1574
|
+
printer.get_message_from_key_with_format(
|
|
1575
|
+
"invalid_file_pattern", file_pattern=file_pattern
|
|
1576
|
+
)
|
|
1577
|
+
)
|
|
1578
|
+
|
|
1579
|
+
# Add new patterns
|
|
1580
|
+
new_patterns_added = memory_manager.add_exclude_files(new_file_patterns)
|
|
1581
|
+
|
|
1582
|
+
if new_patterns_added:
|
|
1583
|
+
result_manager.add_result(
|
|
1584
|
+
content=f"Added exclude files: {new_patterns_added}",
|
|
1585
|
+
meta={"action": "exclude_files", "input": {"query": new_patterns_added}},
|
|
1586
|
+
)
|
|
1587
|
+
print(f"Added exclude files: {new_patterns_added}")
|
|
2848
1588
|
else:
|
|
2849
|
-
result_manager.add_result(
|
|
2850
|
-
"
|
|
2851
|
-
"input": {
|
|
2852
|
-
|
|
2853
|
-
}
|
|
2854
|
-
})
|
|
1589
|
+
result_manager.add_result(
|
|
1590
|
+
content=f"All specified files are already in the exclude list.",
|
|
1591
|
+
meta={"action": "exclude_files", "input": {"query": new_file_patterns}},
|
|
1592
|
+
)
|
|
2855
1593
|
print("All specified files are already in the exclude list.")
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
1594
|
|
|
2859
|
-
|
|
1595
|
+
|
|
2860
1596
|
def index_build():
|
|
1597
|
+
memory = get_memory()
|
|
2861
1598
|
conf = memory.get("conf", {})
|
|
2862
1599
|
yaml_config = {
|
|
2863
1600
|
"include_file": ["./base/base.yml"],
|
|
@@ -2872,17 +1609,18 @@ def index_build():
|
|
|
2872
1609
|
yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
|
|
2873
1610
|
yaml_file = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
2874
1611
|
|
|
2875
|
-
with open(yaml_file, "w",encoding="utf-8") as f:
|
|
1612
|
+
with open(yaml_file, "w", encoding="utf-8") as f:
|
|
2876
1613
|
f.write(yaml_content)
|
|
2877
|
-
try:
|
|
2878
|
-
auto_coder_main(["index", "--file", yaml_file])
|
|
1614
|
+
try:
|
|
1615
|
+
auto_coder_main(["index", "--file", yaml_file])
|
|
2879
1616
|
completer.refresh_files()
|
|
2880
1617
|
finally:
|
|
2881
1618
|
os.remove(yaml_file)
|
|
2882
1619
|
|
|
2883
1620
|
|
|
2884
|
-
def get_final_config()->AutoCoderArgs:
|
|
2885
|
-
|
|
1621
|
+
def get_final_config() -> AutoCoderArgs:
|
|
1622
|
+
memory_manager = get_memory_manager()
|
|
1623
|
+
conf = memory_manager.get_all_config()
|
|
2886
1624
|
yaml_config = {
|
|
2887
1625
|
"include_file": ["./base/base.yml"],
|
|
2888
1626
|
"auto_merge": conf.get("auto_merge", "editblock"),
|
|
@@ -2890,9 +1628,9 @@ def get_final_config()->AutoCoderArgs:
|
|
|
2890
1628
|
"skip_build_index": conf.get("skip_build_index", "true") == "true",
|
|
2891
1629
|
"skip_confirm": conf.get("skip_confirm", "true") == "true",
|
|
2892
1630
|
"silence": conf.get("silence", "true") == "true",
|
|
2893
|
-
"include_project_structure": conf.get("include_project_structure", "
|
|
1631
|
+
"include_project_structure": conf.get("include_project_structure", "false")
|
|
2894
1632
|
== "true",
|
|
2895
|
-
"exclude_files":
|
|
1633
|
+
"exclude_files": memory_manager.get_exclude_files(),
|
|
2896
1634
|
}
|
|
2897
1635
|
for key, value in conf.items():
|
|
2898
1636
|
converted_value = convert_config_value(key, value)
|
|
@@ -2901,7 +1639,7 @@ def get_final_config()->AutoCoderArgs:
|
|
|
2901
1639
|
|
|
2902
1640
|
temp_yaml = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
2903
1641
|
try:
|
|
2904
|
-
with open(temp_yaml, "w",encoding="utf-8") as f:
|
|
1642
|
+
with open(temp_yaml, "w", encoding="utf-8") as f:
|
|
2905
1643
|
f.write(convert_yaml_config_to_str(yaml_config=yaml_config))
|
|
2906
1644
|
args = convert_yaml_to_config(temp_yaml)
|
|
2907
1645
|
finally:
|
|
@@ -2909,18 +1647,31 @@ def get_final_config()->AutoCoderArgs:
|
|
|
2909
1647
|
os.remove(temp_yaml)
|
|
2910
1648
|
return args
|
|
2911
1649
|
|
|
1650
|
+
|
|
2912
1651
|
def help(query: str):
|
|
2913
|
-
from autocoder.common.auto_configure import
|
|
1652
|
+
from autocoder.common.auto_configure import (
|
|
1653
|
+
ConfigAutoTuner,
|
|
1654
|
+
MemoryConfig,
|
|
1655
|
+
AutoConfigRequest,
|
|
1656
|
+
)
|
|
1657
|
+
|
|
1658
|
+
memory_manager = get_memory_manager()
|
|
1659
|
+
memory = get_memory()
|
|
2914
1660
|
args = get_final_config()
|
|
2915
|
-
product_mode =
|
|
1661
|
+
product_mode = memory_manager.get_config("product_mode", "lite")
|
|
2916
1662
|
llm = get_single_llm(args.chat_model or args.model, product_mode=product_mode)
|
|
2917
|
-
auto_config_tuner = ConfigAutoTuner(
|
|
2918
|
-
|
|
1663
|
+
auto_config_tuner = ConfigAutoTuner(
|
|
1664
|
+
args=args,
|
|
1665
|
+
llm=llm,
|
|
1666
|
+
memory_config=MemoryConfig(memory=memory, save_memory_func=save_memory),
|
|
1667
|
+
)
|
|
1668
|
+
auto_config_tuner.tune(AutoConfigRequest(query=query))
|
|
1669
|
+
|
|
2919
1670
|
|
|
2920
|
-
@run_in_raw_thread()
|
|
2921
1671
|
def index_export(path: str):
|
|
2922
1672
|
from autocoder.common.index_import_export import export_index
|
|
2923
1673
|
from autocoder.common.printer import Printer
|
|
1674
|
+
|
|
2924
1675
|
printer = Printer()
|
|
2925
1676
|
project_root = os.getcwd()
|
|
2926
1677
|
if export_index(project_root, path):
|
|
@@ -2928,10 +1679,11 @@ def index_export(path: str):
|
|
|
2928
1679
|
else:
|
|
2929
1680
|
printer.print_in_terminal("index_export_fail", path=path)
|
|
2930
1681
|
|
|
2931
|
-
|
|
1682
|
+
|
|
2932
1683
|
def index_import(path: str):
|
|
2933
1684
|
from autocoder.common.index_import_export import import_index
|
|
2934
1685
|
from autocoder.common.printer import Printer
|
|
1686
|
+
|
|
2935
1687
|
printer = Printer()
|
|
2936
1688
|
project_root = os.getcwd()
|
|
2937
1689
|
if import_index(project_root, path):
|
|
@@ -2939,7 +1691,7 @@ def index_import(path: str):
|
|
|
2939
1691
|
else:
|
|
2940
1692
|
printer.print_in_terminal("index_import_fail", path=path)
|
|
2941
1693
|
|
|
2942
|
-
|
|
1694
|
+
|
|
2943
1695
|
def index_query(query: str):
|
|
2944
1696
|
from autocoder.index.entry import build_index_and_filter_files
|
|
2945
1697
|
from autocoder.pyproject import PyProject
|
|
@@ -2949,7 +1701,9 @@ def index_query(query: str):
|
|
|
2949
1701
|
config = get_final_config()
|
|
2950
1702
|
config.query = query
|
|
2951
1703
|
config.skip_filter_index = False
|
|
2952
|
-
llm = get_single_llm(
|
|
1704
|
+
llm = get_single_llm(
|
|
1705
|
+
config.chat_model or config.model, product_mode=config.product_mode
|
|
1706
|
+
)
|
|
2953
1707
|
|
|
2954
1708
|
if config.project_type == "ts":
|
|
2955
1709
|
pp = TSProject(args=config, llm=llm)
|
|
@@ -2958,264 +1712,79 @@ def index_query(query: str):
|
|
|
2958
1712
|
else:
|
|
2959
1713
|
pp = SuffixProject(args=config, llm=llm, file_filter=None)
|
|
2960
1714
|
pp.run()
|
|
2961
|
-
sources = pp.sources
|
|
2962
|
-
source_code_list = build_index_and_filter_files(
|
|
2963
|
-
|
|
1715
|
+
sources = pp.sources
|
|
1716
|
+
source_code_list = build_index_and_filter_files(
|
|
1717
|
+
llm=llm, args=config, sources=sources
|
|
1718
|
+
)
|
|
1719
|
+
return source_code_list
|
|
1720
|
+
|
|
2964
1721
|
|
|
2965
1722
|
def list_files():
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
1723
|
+
"""
|
|
1724
|
+
处理文件列表命令,使用 ListFilesHandler 进行统一处理
|
|
1725
|
+
"""
|
|
1726
|
+
from autocoder.common.file_handler import ListFilesHandler
|
|
2969
1727
|
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
title="Current Files", show_header=True, header_style="bold magenta"
|
|
2973
|
-
)
|
|
2974
|
-
table.add_column("File", style="green")
|
|
2975
|
-
for file in current_files:
|
|
2976
|
-
table.add_row(os.path.relpath(file, project_root))
|
|
2977
|
-
console.print(Panel(table, border_style="blue"))
|
|
2978
|
-
else:
|
|
2979
|
-
console.print(
|
|
2980
|
-
Panel(
|
|
2981
|
-
"No files in the current session.",
|
|
2982
|
-
title="Current Files",
|
|
2983
|
-
border_style="yellow",
|
|
2984
|
-
)
|
|
2985
|
-
)
|
|
1728
|
+
handler = ListFilesHandler()
|
|
1729
|
+
handler.handle_list_files_command()
|
|
2986
1730
|
|
|
2987
1731
|
|
|
2988
1732
|
def gen_and_exec_shell_command(query: str):
|
|
2989
|
-
from rich.prompt import Confirm
|
|
2990
|
-
from autocoder.common.printer import Printer
|
|
2991
|
-
from rich.console import Console
|
|
2992
|
-
|
|
2993
1733
|
printer = Printer()
|
|
2994
1734
|
console = Console()
|
|
2995
1735
|
# Generate the shell script
|
|
2996
|
-
shell_script = generate_shell_command(query)
|
|
1736
|
+
shell_script = generate_shell_command(query)
|
|
2997
1737
|
|
|
2998
1738
|
# Ask for confirmation using rich
|
|
2999
1739
|
if Confirm.ask(
|
|
3000
|
-
printer.get_message_from_key("confirm_execute_shell_script"),
|
|
3001
|
-
default=False
|
|
1740
|
+
printer.get_message_from_key("confirm_execute_shell_script"), default=False
|
|
3002
1741
|
):
|
|
3003
1742
|
execute_shell_command(shell_script)
|
|
3004
1743
|
else:
|
|
3005
1744
|
console.print(
|
|
3006
1745
|
Panel(
|
|
3007
1746
|
printer.get_message_from_key("shell_script_not_executed"),
|
|
3008
|
-
border_style="yellow"
|
|
1747
|
+
border_style="yellow",
|
|
3009
1748
|
)
|
|
3010
1749
|
)
|
|
3011
1750
|
|
|
3012
1751
|
|
|
3013
1752
|
def lib_command(args: List[str]):
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
llm_friendly_packages_dir = os.path.join(lib_dir, "llm_friendly_packages")
|
|
3017
|
-
|
|
3018
|
-
if not os.path.exists(lib_dir):
|
|
3019
|
-
os.makedirs(lib_dir)
|
|
3020
|
-
|
|
3021
|
-
if "libs" not in memory:
|
|
3022
|
-
memory["libs"] = {}
|
|
3023
|
-
|
|
3024
|
-
if not args:
|
|
3025
|
-
console.print(
|
|
3026
|
-
"Please specify a subcommand: /add, /remove, /list, /list_all, /set-proxy, /refresh, or /get"
|
|
3027
|
-
)
|
|
3028
|
-
return
|
|
3029
|
-
|
|
3030
|
-
subcommand = args[0]
|
|
3031
|
-
|
|
3032
|
-
if subcommand == "/add":
|
|
3033
|
-
if len(args) < 2:
|
|
3034
|
-
console.print("Please specify a library name to add")
|
|
3035
|
-
return
|
|
3036
|
-
lib_name = args[1].strip()
|
|
3037
|
-
|
|
3038
|
-
# Clone the repository if it doesn't exist
|
|
3039
|
-
if not os.path.exists(llm_friendly_packages_dir):
|
|
3040
|
-
console.print("Cloning llm_friendly_packages repository...")
|
|
3041
|
-
try:
|
|
3042
|
-
proxy_url = memory.get(
|
|
3043
|
-
"lib-proxy", "https://github.com/allwefantasy/llm_friendly_packages"
|
|
3044
|
-
)
|
|
3045
|
-
git.Repo.clone_from(
|
|
3046
|
-
proxy_url,
|
|
3047
|
-
llm_friendly_packages_dir,
|
|
3048
|
-
)
|
|
3049
|
-
console.print(
|
|
3050
|
-
"Successfully cloned llm_friendly_packages repository")
|
|
3051
|
-
except git.exc.GitCommandError as e:
|
|
3052
|
-
console.print(f"Error cloning repository: {e}")
|
|
3053
|
-
|
|
3054
|
-
if lib_name in memory["libs"]:
|
|
3055
|
-
console.print(f"Library {lib_name} is already added")
|
|
3056
|
-
else:
|
|
3057
|
-
memory["libs"][lib_name] = {}
|
|
3058
|
-
console.print(f"Added library: {lib_name}")
|
|
3059
|
-
|
|
3060
|
-
save_memory()
|
|
3061
|
-
|
|
3062
|
-
elif subcommand == "/remove":
|
|
3063
|
-
if len(args) < 2:
|
|
3064
|
-
console.print("Please specify a library name to remove")
|
|
3065
|
-
return
|
|
3066
|
-
lib_name = args[1].strip()
|
|
3067
|
-
if lib_name in memory["libs"]:
|
|
3068
|
-
del memory["libs"][lib_name]
|
|
3069
|
-
console.print(f"Removed library: {lib_name}")
|
|
3070
|
-
save_memory()
|
|
3071
|
-
else:
|
|
3072
|
-
console.print(f"Library {lib_name} is not in the list")
|
|
3073
|
-
|
|
3074
|
-
elif subcommand == "/list":
|
|
3075
|
-
if memory["libs"]:
|
|
3076
|
-
table = Table(title="Added Libraries")
|
|
3077
|
-
table.add_column("Library Name", style="cyan")
|
|
3078
|
-
for lib_name in memory["libs"]:
|
|
3079
|
-
table.add_row(lib_name)
|
|
3080
|
-
console.print(table)
|
|
3081
|
-
else:
|
|
3082
|
-
console.print("No libraries added yet")
|
|
3083
|
-
|
|
3084
|
-
elif subcommand == "/list_all":
|
|
3085
|
-
if not os.path.exists(llm_friendly_packages_dir):
|
|
3086
|
-
console.print("llm_friendly_packages repository does not exist. Please run /lib /add <library_name> command first to clone it.")
|
|
3087
|
-
return
|
|
3088
|
-
|
|
3089
|
-
available_libs = []
|
|
3090
|
-
|
|
3091
|
-
# 遍历所有domain目录
|
|
3092
|
-
for domain in os.listdir(llm_friendly_packages_dir):
|
|
3093
|
-
domain_path = os.path.join(llm_friendly_packages_dir, domain)
|
|
3094
|
-
if os.path.isdir(domain_path):
|
|
3095
|
-
# 遍历所有username目录
|
|
3096
|
-
for username in os.listdir(domain_path):
|
|
3097
|
-
username_path = os.path.join(domain_path, username)
|
|
3098
|
-
if os.path.isdir(username_path):
|
|
3099
|
-
# 遍历所有lib_name目录
|
|
3100
|
-
for lib_name in os.listdir(username_path):
|
|
3101
|
-
lib_path = os.path.join(username_path, lib_name)
|
|
3102
|
-
if os.path.isdir(lib_path):
|
|
3103
|
-
# 检查是否有Markdown文件
|
|
3104
|
-
has_md_files = False
|
|
3105
|
-
for root, _, files in os.walk(lib_path):
|
|
3106
|
-
if any(file.endswith('.md') for file in files):
|
|
3107
|
-
has_md_files = True
|
|
3108
|
-
break
|
|
3109
|
-
|
|
3110
|
-
if has_md_files:
|
|
3111
|
-
available_libs.append({
|
|
3112
|
-
"domain": domain,
|
|
3113
|
-
"username": username,
|
|
3114
|
-
"lib_name": lib_name,
|
|
3115
|
-
"full_path": f"{username}/{lib_name}",
|
|
3116
|
-
"is_added": lib_name in memory["libs"]
|
|
3117
|
-
})
|
|
3118
|
-
|
|
3119
|
-
if available_libs:
|
|
3120
|
-
table = Table(title="Available Libraries")
|
|
3121
|
-
table.add_column("Domain", style="blue")
|
|
3122
|
-
table.add_column("Username", style="green")
|
|
3123
|
-
table.add_column("Library Name", style="cyan")
|
|
3124
|
-
table.add_column("Full Path", style="magenta")
|
|
3125
|
-
table.add_column("Status", style="yellow")
|
|
3126
|
-
|
|
3127
|
-
# 按domain和username分组排序
|
|
3128
|
-
available_libs.sort(key=lambda x: (x["domain"], x["username"], x["lib_name"]))
|
|
3129
|
-
|
|
3130
|
-
for lib in available_libs:
|
|
3131
|
-
status = "[green]Added[/green]" if lib["is_added"] else "[white]Not Added[/white]"
|
|
3132
|
-
table.add_row(
|
|
3133
|
-
lib["domain"],
|
|
3134
|
-
lib["username"],
|
|
3135
|
-
lib["lib_name"],
|
|
3136
|
-
lib["full_path"],
|
|
3137
|
-
status
|
|
3138
|
-
)
|
|
3139
|
-
|
|
3140
|
-
console.print(table)
|
|
3141
|
-
else:
|
|
3142
|
-
console.print("No available libraries found in the repository.")
|
|
3143
|
-
|
|
3144
|
-
elif subcommand == "/set-proxy":
|
|
3145
|
-
if len(args) == 1:
|
|
3146
|
-
current_proxy = memory.get("lib-proxy", "No proxy set")
|
|
3147
|
-
console.print(f"Current proxy: {current_proxy}")
|
|
3148
|
-
elif len(args) == 2:
|
|
3149
|
-
proxy_url = args[1]
|
|
3150
|
-
memory["lib-proxy"] = proxy_url
|
|
3151
|
-
console.print(f"Set proxy to: {proxy_url}")
|
|
3152
|
-
save_memory()
|
|
3153
|
-
else:
|
|
3154
|
-
console.print("Invalid number of arguments for /set-proxy")
|
|
3155
|
-
|
|
3156
|
-
elif subcommand == "/refresh":
|
|
3157
|
-
if os.path.exists(llm_friendly_packages_dir):
|
|
3158
|
-
try:
|
|
3159
|
-
repo = git.Repo(llm_friendly_packages_dir)
|
|
3160
|
-
origin = repo.remotes.origin
|
|
3161
|
-
proxy_url = memory.get("lib-proxy")
|
|
3162
|
-
|
|
3163
|
-
current_url = origin.url
|
|
3164
|
-
|
|
3165
|
-
if proxy_url and proxy_url != current_url:
|
|
3166
|
-
new_url = proxy_url
|
|
3167
|
-
origin.set_url(new_url)
|
|
3168
|
-
console.print(f"Updated remote URL to: {new_url}")
|
|
3169
|
-
|
|
3170
|
-
origin.pull()
|
|
3171
|
-
console.print(
|
|
3172
|
-
"Successfully updated llm_friendly_packages repository")
|
|
3173
|
-
|
|
3174
|
-
except git.exc.GitCommandError as e:
|
|
3175
|
-
console.print(f"Error updating repository: {e}")
|
|
3176
|
-
else:
|
|
3177
|
-
console.print(
|
|
3178
|
-
"llm_friendly_packages repository does not exist. Please run /lib /add <library_name> command first to clone it."
|
|
3179
|
-
)
|
|
1753
|
+
"""
|
|
1754
|
+
处理库管理命令,使用 LibHandler 进行统一处理
|
|
3180
1755
|
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
package_name = args[1].strip()
|
|
3186
|
-
docs = get_llm_friendly_package_docs(package_name, return_paths=True)
|
|
3187
|
-
if docs:
|
|
3188
|
-
table = Table(title=f"Markdown Files for {package_name}")
|
|
3189
|
-
table.add_column("File Path", style="cyan")
|
|
3190
|
-
for doc in docs:
|
|
3191
|
-
table.add_row(doc)
|
|
3192
|
-
console.print(table)
|
|
3193
|
-
else:
|
|
3194
|
-
console.print(
|
|
3195
|
-
f"No markdown files found for package: {package_name}")
|
|
1756
|
+
Args:
|
|
1757
|
+
args: 命令参数列表
|
|
1758
|
+
"""
|
|
1759
|
+
from autocoder.common.file_handler import LibHandler
|
|
3196
1760
|
|
|
3197
|
-
|
|
3198
|
-
|
|
1761
|
+
handler = LibHandler()
|
|
1762
|
+
handler.handle_lib_command(args)
|
|
3199
1763
|
|
|
3200
1764
|
|
|
3201
1765
|
def execute_shell_command(command: str):
|
|
3202
1766
|
from autocoder.common.shells import execute_shell_command as shell_exec
|
|
1767
|
+
|
|
3203
1768
|
shell_exec(command)
|
|
3204
1769
|
|
|
3205
1770
|
|
|
3206
1771
|
def conf_export(path: str):
|
|
3207
1772
|
from autocoder.common.conf_import_export import export_conf
|
|
1773
|
+
|
|
3208
1774
|
export_conf(os.getcwd(), path)
|
|
3209
1775
|
|
|
1776
|
+
|
|
3210
1777
|
def conf_import(path: str):
|
|
3211
1778
|
from autocoder.common.conf_import_export import import_conf
|
|
1779
|
+
|
|
3212
1780
|
import_conf(os.getcwd(), path)
|
|
3213
1781
|
|
|
1782
|
+
|
|
3214
1783
|
def generate_new_yaml(query: str):
|
|
3215
1784
|
memory = get_memory()
|
|
3216
|
-
conf = memory.get("conf",{})
|
|
3217
|
-
current_files = memory.get("current_files",{}).get("files",[])
|
|
3218
|
-
auto_coder_main(["next", "chat_action"])
|
|
1785
|
+
conf = memory.get("conf", {})
|
|
1786
|
+
current_files = memory.get("current_files", {}).get("files", [])
|
|
1787
|
+
auto_coder_main(["next", "chat_action"])
|
|
3219
1788
|
latest_yaml_file = get_last_yaml_file("actions")
|
|
3220
1789
|
if latest_yaml_file:
|
|
3221
1790
|
yaml_config = {
|
|
@@ -3225,11 +1794,11 @@ def generate_new_yaml(query: str):
|
|
|
3225
1794
|
"skip_build_index": conf.get("skip_build_index", "true") == "true",
|
|
3226
1795
|
"skip_confirm": conf.get("skip_confirm", "true") == "true",
|
|
3227
1796
|
"silence": conf.get("silence", "true") == "true",
|
|
3228
|
-
"include_project_structure": conf.get("include_project_structure", "
|
|
1797
|
+
"include_project_structure": conf.get("include_project_structure", "false")
|
|
3229
1798
|
== "true",
|
|
3230
1799
|
"exclude_files": memory.get("exclude_files", []),
|
|
3231
1800
|
}
|
|
3232
|
-
yaml_config["context"] = ""
|
|
1801
|
+
yaml_config["context"] = ""
|
|
3233
1802
|
for key, value in conf.items():
|
|
3234
1803
|
converted_value = convert_config_value(key, value)
|
|
3235
1804
|
if converted_value is not None:
|
|
@@ -3240,310 +1809,356 @@ def generate_new_yaml(query: str):
|
|
|
3240
1809
|
)
|
|
3241
1810
|
# handle image
|
|
3242
1811
|
v = Image.convert_image_paths_from(query)
|
|
3243
|
-
yaml_config["query"] = v
|
|
1812
|
+
yaml_config["query"] = v
|
|
3244
1813
|
|
|
3245
|
-
yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
|
|
1814
|
+
yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
|
|
3246
1815
|
|
|
3247
1816
|
execute_file = os.path.join("actions", latest_yaml_file)
|
|
3248
|
-
with open(os.path.join(execute_file), "w",encoding="utf-8") as f:
|
|
1817
|
+
with open(os.path.join(execute_file), "w", encoding="utf-8") as f:
|
|
3249
1818
|
f.write(yaml_content)
|
|
3250
|
-
return execute_file,convert_yaml_to_config(execute_file)
|
|
3251
|
-
|
|
3252
|
-
@run_in_raw_thread()
|
|
3253
|
-
def auto_command(query: str,extra_args: Dict[str,Any]={}):
|
|
3254
|
-
"""处理/auto指令"""
|
|
3255
|
-
args = get_final_config()
|
|
3256
|
-
memory = get_memory()
|
|
3257
|
-
if args.enable_agentic_edit:
|
|
3258
|
-
from autocoder.run_context import get_run_context,RunMode
|
|
3259
|
-
execute_file,args = generate_new_yaml(query)
|
|
3260
|
-
args.file = execute_file
|
|
3261
|
-
current_files = memory.get("current_files",{}).get("files",[])
|
|
3262
|
-
sources = []
|
|
3263
|
-
for file in current_files:
|
|
3264
|
-
try:
|
|
3265
|
-
with open(file,"r",encoding="utf-8") as f:
|
|
3266
|
-
sources.append(SourceCode(module_name=file,source_code=f.read()))
|
|
3267
|
-
except Exception as e:
|
|
3268
|
-
global_logger.error(f"Failed to read file {file}: {e}")
|
|
3269
|
-
|
|
3270
|
-
llm = get_single_llm(args.code_model or args.model,product_mode=args.product_mode)
|
|
3271
|
-
conversation_history = extra_args.get("conversations",[])
|
|
1819
|
+
return execute_file, convert_yaml_to_config(execute_file)
|
|
3272
1820
|
|
|
3273
|
-
command_infos = parse_query(query)
|
|
3274
1821
|
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
)
|
|
3279
|
-
|
|
3280
|
-
## web 模式会自己管理对话,所以这里总是设置为新对话
|
|
3281
|
-
if get_run_context().mode == RunMode.WEB:
|
|
3282
|
-
command_infos = {
|
|
3283
|
-
"new":{
|
|
3284
|
-
"args":[query]
|
|
3285
|
-
}
|
|
3286
|
-
}
|
|
3287
|
-
|
|
3288
|
-
task_query = query
|
|
3289
|
-
|
|
3290
|
-
if "new" in command_infos:
|
|
3291
|
-
conversation_config.action = "new"
|
|
3292
|
-
task_query = " ".join(command_infos["new"]["args"])
|
|
3293
|
-
|
|
3294
|
-
if "resume" in command_infos:
|
|
3295
|
-
conversation_config.action = "resume"
|
|
3296
|
-
conversation_config.conversation_id = command_infos["resume"]["args"][0]
|
|
3297
|
-
task_query = " ".join(command_infos["resume"]["args"][1:])
|
|
1822
|
+
def handle_conversation_actions(conversation_config) -> bool:
|
|
1823
|
+
"""
|
|
1824
|
+
处理对话列表和创建新对话的操作
|
|
3298
1825
|
|
|
3299
|
-
|
|
3300
|
-
|
|
1826
|
+
Args:
|
|
1827
|
+
conversation_config: 对话配置对象
|
|
3301
1828
|
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
1829
|
+
Returns:
|
|
1830
|
+
bool: 如果处理了特殊操作(LIST或NEW without input)返回True,否则返回False
|
|
1831
|
+
"""
|
|
1832
|
+
if not conversation_config:
|
|
1833
|
+
return False
|
|
3306
1834
|
|
|
3307
|
-
|
|
1835
|
+
console = Console()
|
|
3308
1836
|
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
if get_run_context().mode == RunMode.TERMINAL:
|
|
3323
|
-
runner = TerminalRunner(llm=llm,
|
|
3324
|
-
args=args,
|
|
3325
|
-
files=SourceCodeList(sources=sources),
|
|
3326
|
-
conversation_history=conversation_history,
|
|
3327
|
-
memory_config=MemoryConfig(memory=memory,
|
|
3328
|
-
save_memory_func=save_memory),
|
|
3329
|
-
command_config=CommandConfig,
|
|
3330
|
-
conversation_name="current",
|
|
3331
|
-
conversation_config=conversation_config
|
|
3332
|
-
)
|
|
3333
|
-
runner.run(AgenticEditRequest(user_input=task_query))
|
|
3334
|
-
|
|
3335
|
-
completer.refresh_files()
|
|
3336
|
-
return
|
|
3337
|
-
|
|
3338
|
-
args = get_final_config()
|
|
3339
|
-
# 准备请求参数
|
|
3340
|
-
request = AutoCommandRequest(
|
|
3341
|
-
user_input=query
|
|
3342
|
-
)
|
|
1837
|
+
# 处理LIST操作
|
|
1838
|
+
if conversation_config.action == ConversationAction.LIST:
|
|
1839
|
+
conversation_manager = get_conversation_manager()
|
|
1840
|
+
conversations = conversation_manager.list_conversations()
|
|
1841
|
+
# 只保留 conversation_id 和 name 字段
|
|
1842
|
+
filtered_conversations = []
|
|
1843
|
+
for conv in conversations:
|
|
1844
|
+
filtered_conv = {
|
|
1845
|
+
"conversation_id": conv.get("conversation_id"),
|
|
1846
|
+
"name": conv.get("name"),
|
|
1847
|
+
}
|
|
1848
|
+
filtered_conversations.append(filtered_conv)
|
|
3343
1849
|
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
commit=commit,
|
|
3356
|
-
help=help,
|
|
3357
|
-
exclude_dirs=exclude_dirs,
|
|
3358
|
-
exclude_files=exclude_files,
|
|
3359
|
-
ask=ask,
|
|
3360
|
-
chat=chat,
|
|
3361
|
-
coding=coding,
|
|
3362
|
-
design=design,
|
|
3363
|
-
summon=summon,
|
|
3364
|
-
lib=lib_command,
|
|
3365
|
-
mcp=mcp,
|
|
3366
|
-
models=manage_models,
|
|
3367
|
-
index_build=index_build,
|
|
3368
|
-
index_query=index_query,
|
|
3369
|
-
execute_shell_command=execute_shell_command,
|
|
3370
|
-
generate_shell_command=generate_shell_command,
|
|
3371
|
-
conf_export=conf_export,
|
|
3372
|
-
conf_import=conf_import,
|
|
3373
|
-
index_export=index_export,
|
|
3374
|
-
index_import=index_import
|
|
3375
|
-
))
|
|
1850
|
+
# 格式化 JSON 输出,使用 JSON 格式渲染而不是 Markdown
|
|
1851
|
+
json_str = json.dumps(filtered_conversations, ensure_ascii=False, indent=4)
|
|
1852
|
+
console.print(
|
|
1853
|
+
Panel(
|
|
1854
|
+
json_str,
|
|
1855
|
+
title="🏁 Task Completion",
|
|
1856
|
+
border_style="green",
|
|
1857
|
+
title_align="left",
|
|
1858
|
+
)
|
|
1859
|
+
)
|
|
1860
|
+
return True
|
|
3376
1861
|
|
|
3377
|
-
#
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
1862
|
+
# 处理NEW操作且没有用户输入
|
|
1863
|
+
if (
|
|
1864
|
+
conversation_config.action == ConversationAction.NEW
|
|
1865
|
+
and not conversation_config.query.strip()
|
|
1866
|
+
):
|
|
1867
|
+
conversation_manager = get_conversation_manager()
|
|
1868
|
+
conversation_id = conversation_manager.create_conversation(
|
|
1869
|
+
name=conversation_config.query or "New Conversation",
|
|
1870
|
+
description=conversation_config.query or "New Conversation",
|
|
1871
|
+
)
|
|
1872
|
+
conversation_manager.set_current_conversation(conversation_id)
|
|
1873
|
+
conversation_message = f"New conversation created: {conversation_manager.get_current_conversation_id()}"
|
|
3389
1874
|
|
|
1875
|
+
# 使用safe console print的简单版本
|
|
1876
|
+
try:
|
|
1877
|
+
console.print(
|
|
1878
|
+
Panel(
|
|
1879
|
+
Markdown(conversation_message),
|
|
1880
|
+
title="🏁 Task Completion",
|
|
1881
|
+
border_style="green",
|
|
1882
|
+
title_align="left",
|
|
1883
|
+
)
|
|
1884
|
+
)
|
|
1885
|
+
except Exception:
|
|
1886
|
+
# fallback to plain text
|
|
1887
|
+
safe_content = conversation_message.replace("[", "\\[").replace("]", "\\]")
|
|
1888
|
+
console.print(
|
|
1889
|
+
Panel(
|
|
1890
|
+
safe_content,
|
|
1891
|
+
title="🏁 Task Completion",
|
|
1892
|
+
border_style="green",
|
|
1893
|
+
title_align="left",
|
|
1894
|
+
)
|
|
1895
|
+
)
|
|
1896
|
+
return True
|
|
1897
|
+
|
|
1898
|
+
return False
|
|
1899
|
+
|
|
1900
|
+
|
|
1901
|
+
# used in /auto command in terminal
|
|
1902
|
+
def run_agentic(
|
|
1903
|
+
query: str,
|
|
1904
|
+
cancel_token: Optional[str] = None,
|
|
1905
|
+
conversation_history: Optional[List[Dict[str, Any]]] = None,
|
|
1906
|
+
):
|
|
1907
|
+
"""处理/auto指令"""
|
|
1908
|
+
agentic = RunAgentic()
|
|
1909
|
+
return agentic.run(query, cancel_token, conversation_history)
|
|
1910
|
+
|
|
1911
|
+
|
|
1912
|
+
def run_agentic_filter(query: str, cancel_token: Optional[str] = None):
|
|
1913
|
+
"""处理/auto指令"""
|
|
1914
|
+
agentic = RunAgentic()
|
|
1915
|
+
return agentic.filter(query, cancel_token)
|
|
1916
|
+
|
|
1917
|
+
|
|
1918
|
+
# used in autocoder/sdk/core/bridge.py
|
|
1919
|
+
def run_auto_command(
|
|
1920
|
+
query: str,
|
|
1921
|
+
pre_commit: bool = False,
|
|
1922
|
+
post_commit: bool = False,
|
|
1923
|
+
pr: bool = False,
|
|
1924
|
+
extra_args: Dict[str, Any] = {},
|
|
1925
|
+
cancel_token: Optional[str] = None,
|
|
1926
|
+
conversation_history: Optional[List[Dict[str, Any]]] = None,
|
|
1927
|
+
system_prompt: Optional[str] = None,
|
|
1928
|
+
conversation_action: ConversationAction = ConversationAction.NEW,
|
|
1929
|
+
conversation_id: Optional[str] = None,
|
|
1930
|
+
is_sub_agent: bool = False,
|
|
1931
|
+
):
|
|
1932
|
+
"""处理/auto指令"""
|
|
1933
|
+
agentic = RunAgentic()
|
|
1934
|
+
for event in agentic.run_with_events(
|
|
1935
|
+
query,
|
|
1936
|
+
pre_commit=pre_commit,
|
|
1937
|
+
post_commit=post_commit,
|
|
1938
|
+
pr=pr,
|
|
1939
|
+
extra_args=extra_args,
|
|
1940
|
+
cancel_token=cancel_token,
|
|
1941
|
+
conversation_history=conversation_history,
|
|
1942
|
+
system_prompt=system_prompt,
|
|
1943
|
+
conversation_action=conversation_action,
|
|
1944
|
+
conversation_id=conversation_id,
|
|
1945
|
+
is_sub_agent=is_sub_agent,
|
|
1946
|
+
):
|
|
1947
|
+
yield event
|
|
3390
1948
|
|
|
3391
1949
|
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
execute_file,args = generate_new_yaml(query)
|
|
3404
|
-
args.file = execute_file
|
|
3405
|
-
current_files = memory.get("current_files",{}).get("files",[])
|
|
1950
|
+
# used in auto-coder.web
|
|
1951
|
+
def auto_command(query: str, extra_args: Dict[str, Any] = {}):
|
|
1952
|
+
"""处理/auto指令"""
|
|
1953
|
+
args = get_final_config()
|
|
1954
|
+
memory = get_memory()
|
|
1955
|
+
if args.enable_agentic_edit:
|
|
1956
|
+
from autocoder.run_context import get_run_context, RunMode
|
|
1957
|
+
|
|
1958
|
+
execute_file, _ = generate_new_yaml(query)
|
|
1959
|
+
args.file = execute_file
|
|
1960
|
+
current_files = memory.get("current_files", {}).get("files", [])
|
|
3406
1961
|
sources = []
|
|
3407
1962
|
for file in current_files:
|
|
3408
1963
|
try:
|
|
3409
|
-
with open(file,"r",encoding="utf-8") as f:
|
|
3410
|
-
sources.append(SourceCode(module_name=file,source_code=f.read()))
|
|
1964
|
+
with open(file, "r", encoding="utf-8") as f:
|
|
1965
|
+
sources.append(SourceCode(module_name=file, source_code=f.read()))
|
|
3411
1966
|
except Exception as e:
|
|
3412
1967
|
global_logger.error(f"Failed to read file {file}: {e}")
|
|
3413
|
-
|
|
3414
|
-
llm = get_single_llm(args.code_model or args.model,product_mode=args.product_mode)
|
|
3415
|
-
conversation_history = extra_args.get("conversations",[])
|
|
3416
1968
|
|
|
3417
|
-
|
|
1969
|
+
try:
|
|
1970
|
+
llm = get_single_llm(
|
|
1971
|
+
args.code_model or args.model, product_mode=args.product_mode
|
|
1972
|
+
)
|
|
1973
|
+
except ValueError as e:
|
|
1974
|
+
console = Console()
|
|
1975
|
+
console.print(
|
|
1976
|
+
Panel(
|
|
1977
|
+
f"[red]LLM Configuration Error:[/red]\n\n{str(e)}",
|
|
1978
|
+
title="[red]Error[/red]",
|
|
1979
|
+
border_style="red",
|
|
1980
|
+
padding=(1, 2),
|
|
1981
|
+
)
|
|
1982
|
+
)
|
|
1983
|
+
return
|
|
1984
|
+
conversation_history = extra_args.get("conversations", [])
|
|
1985
|
+
|
|
1986
|
+
command_infos = parse_query(query)
|
|
3418
1987
|
|
|
3419
1988
|
# terminal 的总是接着上次对话, 所以这里总是设置为 resume
|
|
3420
1989
|
conversation_config = AgenticEditConversationConfig(
|
|
3421
|
-
action=
|
|
1990
|
+
action=ConversationAction.RESUME
|
|
3422
1991
|
)
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
"args":[query]
|
|
3429
|
-
}
|
|
3430
|
-
}
|
|
3431
|
-
|
|
3432
|
-
task_query = query
|
|
3433
|
-
|
|
3434
|
-
if "new" in command_infos:
|
|
3435
|
-
conversation_config.action = "new"
|
|
1992
|
+
|
|
1993
|
+
task_query = query
|
|
1994
|
+
|
|
1995
|
+
if "new" in command_infos:
|
|
1996
|
+
conversation_config.action = ConversationAction.NEW
|
|
3436
1997
|
task_query = " ".join(command_infos["new"]["args"])
|
|
3437
|
-
|
|
1998
|
+
|
|
3438
1999
|
if "resume" in command_infos:
|
|
3439
|
-
conversation_config.action =
|
|
3440
|
-
conversation_config.conversation_id = command_infos["resume"]["args"][0]
|
|
3441
|
-
task_query = " ".join(command_infos["resume"]["args"][1:])
|
|
2000
|
+
conversation_config.action = ConversationAction.RESUME
|
|
2001
|
+
conversation_config.conversation_id = command_infos["resume"]["args"][0]
|
|
2002
|
+
task_query = " ".join(command_infos["resume"]["args"][1:])
|
|
3442
2003
|
|
|
3443
2004
|
if "list" in command_infos:
|
|
3444
|
-
conversation_config.action =
|
|
2005
|
+
conversation_config.action = ConversationAction.LIST
|
|
3445
2006
|
|
|
3446
|
-
|
|
3447
2007
|
if "command" in command_infos:
|
|
3448
|
-
conversation_config.action =
|
|
2008
|
+
conversation_config.action = ConversationAction.COMMAND
|
|
3449
2009
|
task_query = render_command_file_with_variables(command_infos)
|
|
3450
|
-
|
|
3451
|
-
conversation_config.query = task_query
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
2010
|
+
|
|
2011
|
+
conversation_config.query = task_query
|
|
2012
|
+
|
|
2013
|
+
# 处理特殊的conversation操作(LIST和NEW without input)
|
|
2014
|
+
if handle_conversation_actions(conversation_config):
|
|
2015
|
+
return conversation_config.conversation_id
|
|
2016
|
+
|
|
2017
|
+
conversation_manager = get_conversation_manager()
|
|
2018
|
+
if conversation_config.action == ConversationAction.NEW:
|
|
2019
|
+
conversation_id = conversation_manager.create_conversation(
|
|
2020
|
+
name=conversation_config.query or "New Conversation",
|
|
2021
|
+
description=conversation_config.query or "New Conversation",
|
|
2022
|
+
)
|
|
2023
|
+
conversation_manager.set_current_conversation(conversation_id)
|
|
2024
|
+
conversation_config.conversation_id = conversation_id
|
|
2025
|
+
|
|
2026
|
+
if (
|
|
2027
|
+
conversation_config.action == ConversationAction.RESUME
|
|
2028
|
+
and conversation_config.conversation_id
|
|
2029
|
+
):
|
|
2030
|
+
conversation_manager.set_current_conversation(
|
|
2031
|
+
conversation_config.conversation_id
|
|
2032
|
+
)
|
|
2033
|
+
|
|
2034
|
+
if (
|
|
2035
|
+
conversation_config.action == ConversationAction.RESUME
|
|
2036
|
+
and not conversation_config.conversation_id
|
|
2037
|
+
and conversation_manager.get_current_conversation_id()
|
|
2038
|
+
):
|
|
2039
|
+
conversation_config.conversation_id = (
|
|
2040
|
+
conversation_manager.get_current_conversation_id()
|
|
2041
|
+
)
|
|
2042
|
+
conversation_manager.set_current_conversation(
|
|
2043
|
+
conversation_config.conversation_id
|
|
2044
|
+
)
|
|
2045
|
+
|
|
2046
|
+
if not conversation_config.conversation_id:
|
|
2047
|
+
conversation_id = conversation_manager.create_conversation(
|
|
2048
|
+
name=conversation_config.query or "New Conversation",
|
|
2049
|
+
description=conversation_config.query or "New Conversation",
|
|
2050
|
+
)
|
|
2051
|
+
conversation_manager.set_current_conversation(conversation_id)
|
|
2052
|
+
conversation_config.conversation_id = conversation_id
|
|
2053
|
+
|
|
2054
|
+
cancel_token = extra_args.get("event_file_id", None)
|
|
2055
|
+
global_logger.info(f"cancel_token: {cancel_token}")
|
|
2056
|
+
if cancel_token:
|
|
2057
|
+
global_cancel.register_token(cancel_token)
|
|
2058
|
+
|
|
2059
|
+
if get_run_context().mode == RunMode.WEB:
|
|
2060
|
+
runner = FileBasedEventRunner(
|
|
2061
|
+
llm=llm,
|
|
2062
|
+
args=args,
|
|
2063
|
+
conversation_config=conversation_config,
|
|
2064
|
+
cancel_token=cancel_token,
|
|
2065
|
+
)
|
|
2066
|
+
runner.run(AgenticEditRequest(user_input=task_query))
|
|
2067
|
+
|
|
2068
|
+
if get_run_context().mode == RunMode.TERMINAL:
|
|
2069
|
+
runner = TerminalRunner(
|
|
2070
|
+
llm=llm,
|
|
2071
|
+
args=args,
|
|
2072
|
+
conversation_config=conversation_config,
|
|
2073
|
+
cancel_token=cancel_token,
|
|
2074
|
+
)
|
|
2075
|
+
runner.run(AgenticEditRequest(user_input=task_query))
|
|
2076
|
+
|
|
3476
2077
|
completer.refresh_files()
|
|
3477
|
-
return
|
|
3478
|
-
|
|
3479
|
-
args = get_final_config()
|
|
2078
|
+
return conversation_config.conversation_id
|
|
2079
|
+
|
|
2080
|
+
args = get_final_config()
|
|
3480
2081
|
# 准备请求参数
|
|
3481
|
-
request = AutoCommandRequest(
|
|
3482
|
-
user_input=query
|
|
3483
|
-
)
|
|
2082
|
+
request = AutoCommandRequest(user_input=query)
|
|
3484
2083
|
|
|
3485
2084
|
# 初始化调优器
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
2085
|
+
try:
|
|
2086
|
+
llm = get_single_llm(
|
|
2087
|
+
args.chat_model or args.model, product_mode=args.product_mode
|
|
2088
|
+
)
|
|
2089
|
+
except ValueError as e:
|
|
2090
|
+
console = Console()
|
|
2091
|
+
console.print(
|
|
2092
|
+
Panel(
|
|
2093
|
+
f"[red]LLM Configuration Error:[/red]\n\n{str(e)}",
|
|
2094
|
+
title="[red]Error[/red]",
|
|
2095
|
+
border_style="red",
|
|
2096
|
+
padding=(1, 2),
|
|
2097
|
+
)
|
|
2098
|
+
)
|
|
2099
|
+
return
|
|
2100
|
+
tuner = CommandAutoTuner(
|
|
2101
|
+
llm,
|
|
2102
|
+
args=args,
|
|
2103
|
+
memory_config=MemoryConfig(memory=memory, save_memory_func=save_memory),
|
|
2104
|
+
command_config=CommandConfig(
|
|
2105
|
+
add_files=add_files,
|
|
2106
|
+
remove_files=remove_files,
|
|
2107
|
+
list_files=list_files,
|
|
2108
|
+
conf=configure,
|
|
2109
|
+
revert=revert,
|
|
2110
|
+
commit=commit,
|
|
2111
|
+
help=help,
|
|
2112
|
+
exclude_dirs=exclude_dirs,
|
|
2113
|
+
exclude_files=exclude_files,
|
|
2114
|
+
ask=ask,
|
|
2115
|
+
chat=chat,
|
|
2116
|
+
coding=coding,
|
|
2117
|
+
design=design,
|
|
2118
|
+
summon=summon,
|
|
2119
|
+
lib=lib_command,
|
|
2120
|
+
mcp=mcp,
|
|
2121
|
+
models=manage_models,
|
|
2122
|
+
index_build=index_build,
|
|
2123
|
+
index_query=index_query,
|
|
2124
|
+
execute_shell_command=execute_shell_command,
|
|
2125
|
+
generate_shell_command=generate_shell_command,
|
|
2126
|
+
conf_export=conf_export,
|
|
2127
|
+
conf_import=conf_import,
|
|
2128
|
+
index_export=index_export,
|
|
2129
|
+
index_import=index_import,
|
|
2130
|
+
),
|
|
2131
|
+
)
|
|
3517
2132
|
|
|
3518
2133
|
# 生成建议
|
|
3519
2134
|
response = tuner.analyze(request)
|
|
3520
2135
|
printer = Printer()
|
|
3521
2136
|
# 显示建议
|
|
3522
|
-
console = Console()
|
|
3523
|
-
console.print(
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
2137
|
+
console = Console()
|
|
2138
|
+
console.print(
|
|
2139
|
+
Panel(
|
|
2140
|
+
Markdown(response.reasoning or ""),
|
|
2141
|
+
title=printer.get_message_from_key_with_format(
|
|
2142
|
+
"auto_command_reasoning_title"
|
|
2143
|
+
),
|
|
2144
|
+
border_style="blue",
|
|
2145
|
+
padding=(1, 2),
|
|
2146
|
+
)
|
|
2147
|
+
)
|
|
3534
2148
|
completer.refresh_files()
|
|
2149
|
+
return None
|
|
3535
2150
|
|
|
3536
2151
|
|
|
3537
2152
|
def render_command_file_with_variables(command_infos: Dict[str, Any]) -> str:
|
|
3538
2153
|
"""
|
|
3539
2154
|
使用 CommandManager 加载并渲染命令文件
|
|
3540
|
-
|
|
2155
|
+
|
|
3541
2156
|
Args:
|
|
3542
2157
|
command_infos: parse_query(query) 的返回结果,包含命令和参数信息
|
|
3543
|
-
|
|
2158
|
+
|
|
3544
2159
|
Returns:
|
|
3545
2160
|
str: 渲染后的文件内容
|
|
3546
|
-
|
|
2161
|
+
|
|
3547
2162
|
Raises:
|
|
3548
2163
|
ValueError: 当参数不足或文件不存在时
|
|
3549
2164
|
Exception: 当渲染过程出现错误时
|
|
@@ -3552,31 +2167,33 @@ def render_command_file_with_variables(command_infos: Dict[str, Any]) -> str:
|
|
|
3552
2167
|
# 获取第一个命令的信息
|
|
3553
2168
|
if not command_infos:
|
|
3554
2169
|
raise ValueError("command_infos 为空,无法获取命令信息")
|
|
3555
|
-
|
|
2170
|
+
|
|
3556
2171
|
# command 的位置参数作为路径
|
|
3557
2172
|
first_command = command_infos["command"]
|
|
3558
|
-
|
|
2173
|
+
|
|
3559
2174
|
# 获取位置参数(文件路径)
|
|
3560
2175
|
args = first_command.get("args", [])
|
|
3561
2176
|
if not args:
|
|
3562
2177
|
raise ValueError("未提供文件路径参数")
|
|
3563
|
-
|
|
2178
|
+
|
|
3564
2179
|
file_path = args[0] # 第一个位置参数作为文件路径
|
|
3565
|
-
|
|
2180
|
+
|
|
3566
2181
|
# 获取关键字参数作为渲染参数
|
|
3567
2182
|
kwargs = first_command.get("kwargs", {})
|
|
3568
|
-
|
|
2183
|
+
|
|
3569
2184
|
# 初始化 CommandManager
|
|
3570
2185
|
command_manager = CommandManager()
|
|
3571
|
-
|
|
2186
|
+
|
|
3572
2187
|
# 使用 read_command_file_with_render 直接读取并渲染命令文件
|
|
3573
|
-
rendered_content = command_manager.read_command_file_with_render(
|
|
2188
|
+
rendered_content = command_manager.read_command_file_with_render(
|
|
2189
|
+
file_path, kwargs
|
|
2190
|
+
)
|
|
3574
2191
|
if rendered_content is None:
|
|
3575
2192
|
raise ValueError(f"无法读取或渲染命令文件: {file_path}")
|
|
3576
|
-
|
|
2193
|
+
|
|
3577
2194
|
global_logger.info(f"成功渲染命令文件: {file_path}, 使用参数: {kwargs}")
|
|
3578
2195
|
return rendered_content
|
|
3579
|
-
|
|
2196
|
+
|
|
3580
2197
|
except Exception as e:
|
|
3581
2198
|
global_logger.error(f"render_command_file_with_variables 执行失败: {str(e)}")
|
|
3582
|
-
raise
|
|
2199
|
+
raise
|