auto-coder 1.0.0__py3-none-any.whl → 2.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of auto-coder might be problematic. Click here for more details.
- auto_coder-2.0.0.dist-info/LICENSE +158 -0
- auto_coder-2.0.0.dist-info/METADATA +558 -0
- auto_coder-2.0.0.dist-info/RECORD +795 -0
- {auto_coder-1.0.0.dist-info → auto_coder-2.0.0.dist-info}/WHEEL +1 -1
- {auto_coder-1.0.0.dist-info → auto_coder-2.0.0.dist-info}/entry_points.txt +3 -3
- autocoder/__init__.py +31 -0
- autocoder/agent/auto_filegroup.py +32 -13
- autocoder/agent/auto_learn_from_commit.py +9 -1
- autocoder/agent/base_agentic/__init__.py +3 -0
- autocoder/agent/base_agentic/agent_hub.py +1 -1
- autocoder/agent/base_agentic/base_agent.py +235 -136
- autocoder/agent/base_agentic/default_tools.py +119 -118
- autocoder/agent/base_agentic/test_base_agent.py +1 -1
- autocoder/agent/base_agentic/tool_registry.py +32 -20
- autocoder/agent/base_agentic/tools/read_file_tool_resolver.py +24 -3
- autocoder/agent/base_agentic/tools/write_to_file_tool_resolver.py +24 -11
- autocoder/agent/base_agentic/types.py +42 -0
- autocoder/agent/entry_command_agent/chat.py +73 -59
- autocoder/auto_coder.py +31 -40
- autocoder/auto_coder_rag.py +11 -1084
- autocoder/auto_coder_runner.py +970 -2345
- autocoder/auto_coder_terminal.py +26 -0
- autocoder/auto_coder_terminal_v3.py +190 -0
- autocoder/chat/conf_command.py +224 -124
- autocoder/chat/models_command.py +361 -299
- autocoder/chat/rules_command.py +79 -31
- autocoder/chat_auto_coder.py +988 -398
- autocoder/chat_auto_coder_lang.py +23 -732
- autocoder/commands/auto_command.py +25 -8
- autocoder/commands/auto_web.py +1 -1
- autocoder/commands/tools.py +44 -44
- autocoder/common/__init__.py +150 -128
- autocoder/common/ac_style_command_parser/__init__.py +39 -2
- autocoder/common/ac_style_command_parser/config.py +422 -0
- autocoder/common/ac_style_command_parser/parser.py +292 -78
- autocoder/common/ac_style_command_parser/test_parser.py +241 -16
- autocoder/common/ac_style_command_parser/test_typed_parser.py +342 -0
- autocoder/common/ac_style_command_parser/typed_parser.py +653 -0
- autocoder/common/action_yml_file_manager.py +25 -13
- autocoder/common/agent_events/__init__.py +52 -0
- autocoder/common/agent_events/agent_event_emitter.py +193 -0
- autocoder/common/agent_events/event_factory.py +177 -0
- autocoder/common/agent_events/examples.py +307 -0
- autocoder/common/agent_events/types.py +113 -0
- autocoder/common/agent_events/utils.py +68 -0
- autocoder/common/agent_hooks/__init__.py +44 -0
- autocoder/common/agent_hooks/examples.py +582 -0
- autocoder/common/agent_hooks/hook_executor.py +217 -0
- autocoder/common/agent_hooks/hook_manager.py +288 -0
- autocoder/common/agent_hooks/types.py +133 -0
- autocoder/common/agent_hooks/utils.py +99 -0
- autocoder/common/agent_query_queue/queue_executor.py +324 -0
- autocoder/common/agent_query_queue/queue_manager.py +325 -0
- autocoder/common/agents/__init__.py +11 -0
- autocoder/common/agents/agent_manager.py +323 -0
- autocoder/common/agents/agent_parser.py +189 -0
- autocoder/common/agents/example_usage.py +344 -0
- autocoder/common/agents/integration_example.py +330 -0
- autocoder/common/agents/test_agent_parser.py +545 -0
- autocoder/common/async_utils.py +101 -0
- autocoder/common/auto_coder_lang.py +23 -972
- autocoder/common/autocoderargs_parser/__init__.py +14 -0
- autocoder/common/autocoderargs_parser/parser.py +184 -0
- autocoder/common/autocoderargs_parser/tests/__init__.py +1 -0
- autocoder/common/autocoderargs_parser/tests/test_args_parser.py +235 -0
- autocoder/common/autocoderargs_parser/tests/test_token_parser.py +195 -0
- autocoder/common/autocoderargs_parser/token_parser.py +290 -0
- autocoder/common/buildin_tokenizer.py +2 -4
- autocoder/common/code_auto_generate.py +149 -74
- autocoder/common/code_auto_generate_diff.py +163 -70
- autocoder/common/code_auto_generate_editblock.py +179 -89
- autocoder/common/code_auto_generate_strict_diff.py +167 -72
- autocoder/common/code_auto_merge_editblock.py +13 -6
- autocoder/common/code_modification_ranker.py +1 -1
- autocoder/common/command_completer.py +3 -3
- autocoder/common/command_file_manager/manager.py +183 -47
- autocoder/common/command_file_manager/test_command_file_manager.py +507 -0
- autocoder/common/command_templates.py +1 -1
- autocoder/common/conf_utils.py +2 -4
- autocoder/common/conversations/config.py +11 -3
- autocoder/common/conversations/get_conversation_manager.py +100 -2
- autocoder/common/conversations/llm_stats_models.py +264 -0
- autocoder/common/conversations/manager.py +112 -28
- autocoder/common/conversations/models.py +16 -2
- autocoder/common/conversations/storage/index_manager.py +134 -10
- autocoder/common/core_config/__init__.py +63 -0
- autocoder/common/core_config/agentic_mode_manager.py +109 -0
- autocoder/common/core_config/base_manager.py +123 -0
- autocoder/common/core_config/compatibility.py +151 -0
- autocoder/common/core_config/config_manager.py +156 -0
- autocoder/common/core_config/conversation_manager.py +31 -0
- autocoder/common/core_config/exclude_manager.py +72 -0
- autocoder/common/core_config/file_manager.py +177 -0
- autocoder/common/core_config/human_as_model_manager.py +129 -0
- autocoder/common/core_config/lib_manager.py +54 -0
- autocoder/common/core_config/main_manager.py +81 -0
- autocoder/common/core_config/mode_manager.py +126 -0
- autocoder/common/core_config/models.py +70 -0
- autocoder/common/core_config/test_memory_manager.py +1056 -0
- autocoder/common/env_manager.py +282 -0
- autocoder/common/env_manager_usage_example.py +211 -0
- autocoder/common/file_checkpoint/conversation_checkpoint.py +19 -19
- autocoder/common/file_checkpoint/manager.py +264 -48
- autocoder/common/file_checkpoint/test_backup.py +1 -18
- autocoder/common/file_checkpoint/test_manager.py +270 -1
- autocoder/common/file_checkpoint/test_store.py +1 -17
- autocoder/common/file_handler/__init__.py +23 -0
- autocoder/common/file_handler/active_context_handler.py +159 -0
- autocoder/common/file_handler/add_files_handler.py +409 -0
- autocoder/common/file_handler/chat_handler.py +180 -0
- autocoder/common/file_handler/coding_handler.py +401 -0
- autocoder/common/file_handler/commit_handler.py +200 -0
- autocoder/common/file_handler/lib_handler.py +156 -0
- autocoder/common/file_handler/list_files_handler.py +111 -0
- autocoder/common/file_handler/mcp_handler.py +268 -0
- autocoder/common/file_handler/models_handler.py +493 -0
- autocoder/common/file_handler/remove_files_handler.py +172 -0
- autocoder/common/git_utils.py +44 -8
- autocoder/common/global_cancel.py +15 -6
- autocoder/common/ignorefiles/test_ignore_file_utils.py +1 -1
- autocoder/common/international/__init__.py +31 -0
- autocoder/common/international/demo_international.py +92 -0
- autocoder/common/international/message_manager.py +157 -0
- autocoder/common/international/messages/__init__.py +56 -0
- autocoder/common/international/messages/async_command_messages.py +507 -0
- autocoder/common/international/messages/auto_coder_messages.py +2208 -0
- autocoder/common/international/messages/chat_auto_coder_messages.py +1547 -0
- autocoder/common/international/messages/command_help_messages.py +986 -0
- autocoder/common/international/messages/conversation_command_messages.py +191 -0
- autocoder/common/international/messages/git_helper_plugin_messages.py +159 -0
- autocoder/common/international/messages/queue_command_messages.py +751 -0
- autocoder/common/international/messages/rules_command_messages.py +77 -0
- autocoder/common/international/messages/sdk_messages.py +1707 -0
- autocoder/common/international/messages/token_helper_plugin_messages.py +361 -0
- autocoder/common/international/messages/tool_display_messages.py +1212 -0
- autocoder/common/international/messages/workflow_exception_messages.py +473 -0
- autocoder/common/international/test_international.py +612 -0
- autocoder/common/linter_core/__init__.py +28 -0
- autocoder/common/linter_core/base_linter.py +61 -0
- autocoder/common/linter_core/config_loader.py +271 -0
- autocoder/common/linter_core/formatters/__init__.py +0 -0
- autocoder/common/linter_core/formatters/base_formatter.py +38 -0
- autocoder/common/linter_core/formatters/raw_formatter.py +17 -0
- autocoder/common/linter_core/linter.py +166 -0
- autocoder/common/linter_core/linter_factory.py +216 -0
- autocoder/common/linter_core/linter_manager.py +333 -0
- autocoder/common/linter_core/linters/__init__.py +9 -0
- autocoder/common/linter_core/linters/java_linter.py +342 -0
- autocoder/common/linter_core/linters/python_linter.py +115 -0
- autocoder/common/linter_core/linters/typescript_linter.py +119 -0
- autocoder/common/linter_core/models/__init__.py +7 -0
- autocoder/common/linter_core/models/lint_result.py +91 -0
- autocoder/common/linter_core/models.py +33 -0
- autocoder/common/linter_core/tests/__init__.py +3 -0
- autocoder/common/linter_core/tests/test_config_loader.py +323 -0
- autocoder/common/linter_core/tests/test_config_loading.py +308 -0
- autocoder/common/linter_core/tests/test_factory_manager.py +234 -0
- autocoder/common/linter_core/tests/test_formatters.py +147 -0
- autocoder/common/linter_core/tests/test_integration.py +317 -0
- autocoder/common/linter_core/tests/test_java_linter.py +496 -0
- autocoder/common/linter_core/tests/test_linters.py +265 -0
- autocoder/common/linter_core/tests/test_models.py +81 -0
- autocoder/common/linter_core/tests/verify_config_loading.py +296 -0
- autocoder/common/linter_core/tests/verify_fixes.py +183 -0
- autocoder/common/llm_friendly_package/__init__.py +31 -0
- autocoder/common/llm_friendly_package/base_manager.py +102 -0
- autocoder/common/llm_friendly_package/docs_manager.py +121 -0
- autocoder/common/llm_friendly_package/library_manager.py +171 -0
- autocoder/common/{llm_friendly_package.py → llm_friendly_package/main_manager.py} +204 -231
- autocoder/common/llm_friendly_package/models.py +40 -0
- autocoder/common/llm_friendly_package/test_llm_friendly_package.py +536 -0
- autocoder/common/llms/__init__.py +15 -0
- autocoder/common/llms/demo_error_handling.py +85 -0
- autocoder/common/llms/factory.py +142 -0
- autocoder/common/llms/manager.py +264 -0
- autocoder/common/llms/pricing.py +121 -0
- autocoder/common/llms/registry.py +288 -0
- autocoder/common/llms/schema.py +77 -0
- autocoder/common/llms/simple_demo.py +45 -0
- autocoder/common/llms/test_quick_model.py +116 -0
- autocoder/common/llms/test_remove_functionality.py +182 -0
- autocoder/common/llms/tests/__init__.py +1 -0
- autocoder/common/llms/tests/test_manager.py +330 -0
- autocoder/common/llms/tests/test_registry.py +364 -0
- autocoder/common/mcp_tools/__init__.py +62 -0
- autocoder/common/{mcp_tools.py → mcp_tools/executor.py} +49 -40
- autocoder/common/{mcp_hub.py → mcp_tools/hub.py} +42 -68
- autocoder/common/{mcp_server_install.py → mcp_tools/installer.py} +16 -28
- autocoder/common/{mcp_server.py → mcp_tools/server.py} +176 -48
- autocoder/common/mcp_tools/test_keyboard_interrupt.py +93 -0
- autocoder/common/mcp_tools/test_mcp_tools.py +391 -0
- autocoder/common/{mcp_server_types.py → mcp_tools/types.py} +121 -48
- autocoder/common/mcp_tools/verify_functionality.py +202 -0
- autocoder/common/model_speed_tester.py +32 -26
- autocoder/common/priority_directory_finder/__init__.py +142 -0
- autocoder/common/priority_directory_finder/examples.py +230 -0
- autocoder/common/priority_directory_finder/finder.py +283 -0
- autocoder/common/priority_directory_finder/models.py +236 -0
- autocoder/common/priority_directory_finder/test_priority_directory_finder.py +431 -0
- autocoder/common/project_scanner/__init__.py +18 -0
- autocoder/common/project_scanner/compat.py +77 -0
- autocoder/common/project_scanner/scanner.py +436 -0
- autocoder/common/project_tracker/__init__.py +27 -0
- autocoder/common/project_tracker/api.py +228 -0
- autocoder/common/project_tracker/demo.py +272 -0
- autocoder/common/project_tracker/tracker.py +487 -0
- autocoder/common/project_tracker/types.py +53 -0
- autocoder/common/pruner/__init__.py +67 -0
- autocoder/common/pruner/agentic_conversation_pruner.py +651 -102
- autocoder/common/pruner/conversation_message_ids_api.py +386 -0
- autocoder/common/pruner/conversation_message_ids_manager.py +347 -0
- autocoder/common/pruner/conversation_message_ids_pruner.py +473 -0
- autocoder/common/pruner/conversation_normalizer.py +347 -0
- autocoder/common/pruner/conversation_pruner.py +26 -6
- autocoder/common/pruner/test_agentic_conversation_pruner.py +554 -112
- autocoder/common/pruner/test_conversation_normalizer.py +502 -0
- autocoder/common/pruner/test_tool_content_detector.py +324 -0
- autocoder/common/pruner/tool_content_detector.py +227 -0
- autocoder/common/pruner/tools/__init__.py +18 -0
- autocoder/common/pruner/tools/query_message_ids.py +264 -0
- autocoder/common/pruner/tools/test_agentic_pruning_logic.py +432 -0
- autocoder/common/pruner/tools/test_message_ids_pruning_only.py +192 -0
- autocoder/common/pull_requests/__init__.py +9 -1
- autocoder/common/pull_requests/utils.py +122 -1
- autocoder/common/rag_manager/rag_manager.py +36 -40
- autocoder/common/rulefiles/__init__.py +53 -1
- autocoder/common/rulefiles/api.py +250 -0
- autocoder/common/rulefiles/core/__init__.py +14 -0
- autocoder/common/rulefiles/core/manager.py +241 -0
- autocoder/common/rulefiles/core/selector.py +805 -0
- autocoder/common/rulefiles/models/__init__.py +20 -0
- autocoder/common/rulefiles/models/index.py +16 -0
- autocoder/common/rulefiles/models/init_rule.py +18 -0
- autocoder/common/rulefiles/models/rule_file.py +18 -0
- autocoder/common/rulefiles/models/rule_relevance.py +14 -0
- autocoder/common/rulefiles/models/summary.py +16 -0
- autocoder/common/rulefiles/test_rulefiles.py +776 -0
- autocoder/common/rulefiles/utils/__init__.py +34 -0
- autocoder/common/rulefiles/utils/monitor.py +86 -0
- autocoder/common/rulefiles/utils/parser.py +230 -0
- autocoder/common/save_formatted_log.py +67 -10
- autocoder/common/search_replace.py +8 -1
- autocoder/common/search_replace_patch/__init__.py +24 -0
- autocoder/common/search_replace_patch/base.py +115 -0
- autocoder/common/search_replace_patch/manager.py +248 -0
- autocoder/common/search_replace_patch/patch_replacer.py +304 -0
- autocoder/common/search_replace_patch/similarity_replacer.py +306 -0
- autocoder/common/search_replace_patch/string_replacer.py +181 -0
- autocoder/common/search_replace_patch/tests/__init__.py +3 -0
- autocoder/common/search_replace_patch/tests/run_tests.py +126 -0
- autocoder/common/search_replace_patch/tests/test_base.py +188 -0
- autocoder/common/search_replace_patch/tests/test_empty_line_insert.py +233 -0
- autocoder/common/search_replace_patch/tests/test_integration.py +389 -0
- autocoder/common/search_replace_patch/tests/test_manager.py +351 -0
- autocoder/common/search_replace_patch/tests/test_patch_replacer.py +316 -0
- autocoder/common/search_replace_patch/tests/test_regex_replacer.py +306 -0
- autocoder/common/search_replace_patch/tests/test_similarity_replacer.py +384 -0
- autocoder/common/shell_commands/__init__.py +197 -0
- autocoder/common/shell_commands/background_process_notifier.py +346 -0
- autocoder/common/shell_commands/command_executor.py +1127 -0
- autocoder/common/shell_commands/error_recovery.py +541 -0
- autocoder/common/shell_commands/exceptions.py +120 -0
- autocoder/common/shell_commands/interactive_executor.py +476 -0
- autocoder/common/shell_commands/interactive_pexpect_process.py +623 -0
- autocoder/common/shell_commands/interactive_process.py +744 -0
- autocoder/common/shell_commands/interactive_session_manager.py +1014 -0
- autocoder/common/shell_commands/monitoring.py +529 -0
- autocoder/common/shell_commands/process_cleanup.py +386 -0
- autocoder/common/shell_commands/process_manager.py +606 -0
- autocoder/common/shell_commands/test_interactive_pexpect_process.py +281 -0
- autocoder/common/shell_commands/tests/__init__.py +6 -0
- autocoder/common/shell_commands/tests/conftest.py +118 -0
- autocoder/common/shell_commands/tests/test_background_process_notifier.py +703 -0
- autocoder/common/shell_commands/tests/test_command_executor.py +448 -0
- autocoder/common/shell_commands/tests/test_error_recovery.py +305 -0
- autocoder/common/shell_commands/tests/test_exceptions.py +299 -0
- autocoder/common/shell_commands/tests/test_execute_batch.py +588 -0
- autocoder/common/shell_commands/tests/test_indented_batch_commands.py +244 -0
- autocoder/common/shell_commands/tests/test_integration.py +664 -0
- autocoder/common/shell_commands/tests/test_monitoring.py +546 -0
- autocoder/common/shell_commands/tests/test_performance.py +632 -0
- autocoder/common/shell_commands/tests/test_process_cleanup.py +397 -0
- autocoder/common/shell_commands/tests/test_process_manager.py +606 -0
- autocoder/common/shell_commands/tests/test_timeout_config.py +343 -0
- autocoder/common/shell_commands/tests/test_timeout_manager.py +520 -0
- autocoder/common/shell_commands/timeout_config.py +315 -0
- autocoder/common/shell_commands/timeout_manager.py +352 -0
- autocoder/common/terminal_paste/__init__.py +14 -0
- autocoder/common/terminal_paste/demo.py +145 -0
- autocoder/common/terminal_paste/demo_paste_functionality.py +95 -0
- autocoder/common/terminal_paste/paste_handler.py +200 -0
- autocoder/common/terminal_paste/paste_manager.py +118 -0
- autocoder/common/terminal_paste/tests/__init__.py +1 -0
- autocoder/common/terminal_paste/tests/test_paste_handler.py +182 -0
- autocoder/common/terminal_paste/tests/test_paste_manager.py +126 -0
- autocoder/common/terminal_paste/utils.py +163 -0
- autocoder/common/test_autocoder_args.py +232 -0
- autocoder/common/test_env_manager.py +173 -0
- autocoder/common/test_env_manager_integration.py +159 -0
- autocoder/common/text_similarity/__init__.py +9 -0
- autocoder/common/text_similarity/demo.py +216 -0
- autocoder/common/text_similarity/examples.py +266 -0
- autocoder/common/text_similarity/test_text_similarity.py +306 -0
- autocoder/common/text_similarity/text_similarity.py +194 -0
- autocoder/common/text_similarity/utils.py +125 -0
- autocoder/common/todos/__init__.py +61 -0
- autocoder/common/todos/cache/__init__.py +16 -0
- autocoder/common/todos/cache/base_cache.py +89 -0
- autocoder/common/todos/cache/cache_manager.py +228 -0
- autocoder/common/todos/cache/memory_cache.py +225 -0
- autocoder/common/todos/config.py +155 -0
- autocoder/common/todos/exceptions.py +35 -0
- autocoder/common/todos/get_todo_manager.py +161 -0
- autocoder/common/todos/manager.py +537 -0
- autocoder/common/todos/models.py +239 -0
- autocoder/common/todos/storage/__init__.py +14 -0
- autocoder/common/todos/storage/base_storage.py +76 -0
- autocoder/common/todos/storage/file_storage.py +278 -0
- autocoder/common/tokens/counter.py +24 -2
- autocoder/common/tools_manager/__init__.py +17 -0
- autocoder/common/tools_manager/examples.py +162 -0
- autocoder/common/tools_manager/manager.py +385 -0
- autocoder/common/tools_manager/models.py +39 -0
- autocoder/common/tools_manager/test_tools_manager.py +303 -0
- autocoder/common/tools_manager/utils.py +191 -0
- autocoder/common/v2/agent/agentic_callbacks.py +270 -0
- autocoder/common/v2/agent/agentic_edit.py +2699 -1856
- autocoder/common/v2/agent/agentic_edit_change_manager.py +474 -0
- autocoder/common/v2/agent/agentic_edit_tools/__init__.py +35 -1
- autocoder/common/v2/agent/agentic_edit_tools/ac_mod_list_tool_resolver.py +279 -0
- autocoder/common/v2/agent/agentic_edit_tools/ac_mod_write_tool_resolver.py +10 -1
- autocoder/common/v2/agent/agentic_edit_tools/background_task_tool_resolver.py +1167 -0
- autocoder/common/v2/agent/agentic_edit_tools/base_tool_resolver.py +2 -2
- autocoder/common/v2/agent/agentic_edit_tools/conversation_message_ids_read_tool_resolver.py +214 -0
- autocoder/common/v2/agent/agentic_edit_tools/conversation_message_ids_write_tool_resolver.py +299 -0
- autocoder/common/v2/agent/agentic_edit_tools/count_tokens_tool_resolver.py +290 -0
- autocoder/common/v2/agent/agentic_edit_tools/execute_command_tool_resolver.py +564 -29
- autocoder/common/v2/agent/agentic_edit_tools/execute_workflow_tool_resolver.py +485 -0
- autocoder/common/v2/agent/agentic_edit_tools/extract_to_text_tool_resolver.py +225 -0
- autocoder/common/v2/agent/agentic_edit_tools/lint_report.py +79 -0
- autocoder/common/v2/agent/agentic_edit_tools/linter_config_models.py +343 -0
- autocoder/common/v2/agent/agentic_edit_tools/linter_enabled_tool_resolver.py +189 -0
- autocoder/common/v2/agent/agentic_edit_tools/list_files_tool_resolver.py +169 -101
- autocoder/common/v2/agent/agentic_edit_tools/load_extra_document_tool_resolver.py +349 -0
- autocoder/common/v2/agent/agentic_edit_tools/read_file_tool_resolver.py +243 -50
- autocoder/common/v2/agent/agentic_edit_tools/replace_in_file_tool_resolver.py +667 -147
- autocoder/common/v2/agent/agentic_edit_tools/run_named_subagents_tool_resolver.py +691 -0
- autocoder/common/v2/agent/agentic_edit_tools/search_files_tool_resolver.py +410 -86
- autocoder/common/v2/agent/agentic_edit_tools/session_interactive_tool_resolver.py +115 -0
- autocoder/common/v2/agent/agentic_edit_tools/session_start_tool_resolver.py +190 -0
- autocoder/common/v2/agent/agentic_edit_tools/session_stop_tool_resolver.py +76 -0
- autocoder/common/v2/agent/agentic_edit_tools/test_write_to_file_tool_resolver.py +207 -192
- autocoder/common/v2/agent/agentic_edit_tools/todo_read_tool_resolver.py +80 -63
- autocoder/common/v2/agent/agentic_edit_tools/todo_write_tool_resolver.py +237 -233
- autocoder/common/v2/agent/agentic_edit_tools/use_mcp_tool_resolver.py +2 -2
- autocoder/common/v2/agent/agentic_edit_tools/web_crawl_tool_resolver.py +557 -0
- autocoder/common/v2/agent/agentic_edit_tools/web_search_tool_resolver.py +600 -0
- autocoder/common/v2/agent/agentic_edit_tools/write_to_file_tool_resolver.py +56 -121
- autocoder/common/v2/agent/agentic_edit_types.py +343 -9
- autocoder/common/v2/agent/runner/__init__.py +3 -3
- autocoder/common/v2/agent/runner/base_runner.py +12 -26
- autocoder/common/v2/agent/runner/{event_runner.py → file_based_event_runner.py} +3 -2
- autocoder/common/v2/agent/runner/sdk_runner.py +150 -8
- autocoder/common/v2/agent/runner/terminal_runner.py +170 -57
- autocoder/common/v2/agent/runner/tool_display.py +557 -159
- autocoder/common/v2/agent/test_agentic_callbacks.py +265 -0
- autocoder/common/v2/agent/test_agentic_edit.py +194 -0
- autocoder/common/v2/agent/tool_caller/__init__.py +24 -0
- autocoder/common/v2/agent/tool_caller/default_tool_resolver_map.py +135 -0
- autocoder/common/v2/agent/tool_caller/integration_test.py +172 -0
- autocoder/common/v2/agent/tool_caller/plugins/__init__.py +14 -0
- autocoder/common/v2/agent/tool_caller/plugins/base_plugin.py +126 -0
- autocoder/common/v2/agent/tool_caller/plugins/examples/__init__.py +13 -0
- autocoder/common/v2/agent/tool_caller/plugins/examples/logging_plugin.py +164 -0
- autocoder/common/v2/agent/tool_caller/plugins/examples/security_filter_plugin.py +198 -0
- autocoder/common/v2/agent/tool_caller/plugins/plugin_interface.py +141 -0
- autocoder/common/v2/agent/tool_caller/test_tool_caller.py +278 -0
- autocoder/common/v2/agent/tool_caller/tool_call_plugin_manager.py +331 -0
- autocoder/common/v2/agent/tool_caller/tool_caller.py +337 -0
- autocoder/common/v2/agent/tool_caller/usage_example.py +193 -0
- autocoder/common/v2/code_agentic_editblock_manager.py +4 -4
- autocoder/common/v2/code_auto_generate.py +136 -78
- autocoder/common/v2/code_auto_generate_diff.py +135 -79
- autocoder/common/v2/code_auto_generate_editblock.py +174 -99
- autocoder/common/v2/code_auto_generate_strict_diff.py +151 -71
- autocoder/common/v2/code_auto_merge.py +1 -1
- autocoder/common/v2/code_auto_merge_editblock.py +13 -1
- autocoder/common/v2/code_diff_manager.py +3 -3
- autocoder/common/v2/code_editblock_manager.py +4 -14
- autocoder/common/v2/code_manager.py +1 -1
- autocoder/common/v2/code_strict_diff_manager.py +2 -2
- autocoder/common/wrap_llm_hint/__init__.py +10 -0
- autocoder/common/wrap_llm_hint/test_wrap_llm_hint.py +1067 -0
- autocoder/common/wrap_llm_hint/utils.py +432 -0
- autocoder/common/wrap_llm_hint/wrap_llm_hint.py +323 -0
- autocoder/completer/__init__.py +8 -0
- autocoder/completer/command_completer_v2.py +1051 -0
- autocoder/default_project/__init__.py +501 -0
- autocoder/dispacher/__init__.py +4 -12
- autocoder/dispacher/actions/action.py +165 -7
- autocoder/dispacher/actions/plugins/action_regex_project.py +2 -2
- autocoder/index/entry.py +116 -124
- autocoder/{agent → index/filter}/agentic_filter.py +322 -333
- autocoder/index/filter/normal_filter.py +5 -11
- autocoder/index/filter/quick_filter.py +1 -1
- autocoder/index/index.py +36 -9
- autocoder/index/tests/__init__.py +1 -0
- autocoder/index/tests/run_tests.py +195 -0
- autocoder/index/tests/test_entry.py +303 -0
- autocoder/index/tests/test_index_manager.py +314 -0
- autocoder/index/tests/test_module_integration.py +300 -0
- autocoder/index/tests/test_symbols_utils.py +183 -0
- autocoder/inner/__init__.py +4 -0
- autocoder/inner/agentic.py +932 -0
- autocoder/inner/async_command_handler.py +992 -0
- autocoder/inner/conversation_command_handlers.py +623 -0
- autocoder/inner/merge_command_handler.py +213 -0
- autocoder/inner/queue_command_handler.py +684 -0
- autocoder/models.py +95 -266
- autocoder/plugins/git_helper_plugin.py +31 -29
- autocoder/plugins/token_helper_plugin.py +65 -46
- autocoder/pyproject/__init__.py +32 -29
- autocoder/rag/agentic_rag.py +215 -75
- autocoder/rag/cache/simple_cache.py +1 -2
- autocoder/rag/loaders/image_loader.py +1 -1
- autocoder/rag/long_context_rag.py +42 -26
- autocoder/rag/qa_conversation_strategy.py +1 -1
- autocoder/rag/terminal/__init__.py +17 -0
- autocoder/rag/terminal/args.py +581 -0
- autocoder/rag/terminal/bootstrap.py +61 -0
- autocoder/rag/terminal/command_handlers.py +653 -0
- autocoder/rag/terminal/formatters/__init__.py +20 -0
- autocoder/rag/terminal/formatters/base.py +70 -0
- autocoder/rag/terminal/formatters/json_format.py +66 -0
- autocoder/rag/terminal/formatters/stream_json.py +95 -0
- autocoder/rag/terminal/formatters/text.py +28 -0
- autocoder/rag/terminal/init.py +120 -0
- autocoder/rag/terminal/utils.py +106 -0
- autocoder/rag/test_agentic_rag.py +389 -0
- autocoder/rag/test_doc_filter.py +3 -3
- autocoder/rag/test_long_context_rag.py +1 -1
- autocoder/rag/test_token_limiter.py +517 -10
- autocoder/rag/token_counter.py +3 -0
- autocoder/rag/token_limiter.py +19 -15
- autocoder/rag/tools/__init__.py +26 -2
- autocoder/rag/tools/bochaai_example.py +343 -0
- autocoder/rag/tools/bochaai_sdk.py +541 -0
- autocoder/rag/tools/metaso_example.py +268 -0
- autocoder/rag/tools/metaso_sdk.py +417 -0
- autocoder/rag/tools/recall_tool.py +28 -7
- autocoder/rag/tools/run_integration_tests.py +204 -0
- autocoder/rag/tools/test_all_providers.py +318 -0
- autocoder/rag/tools/test_bochaai_integration.py +482 -0
- autocoder/rag/tools/test_final_integration.py +215 -0
- autocoder/rag/tools/test_metaso_integration.py +424 -0
- autocoder/rag/tools/test_metaso_real.py +171 -0
- autocoder/rag/tools/test_web_crawl_tool.py +639 -0
- autocoder/rag/tools/test_web_search_tool.py +509 -0
- autocoder/rag/tools/todo_read_tool.py +202 -0
- autocoder/rag/tools/todo_write_tool.py +412 -0
- autocoder/rag/tools/web_crawl_tool.py +634 -0
- autocoder/rag/tools/web_search_tool.py +558 -0
- autocoder/rag/tools/web_tools_example.py +119 -0
- autocoder/rag/types.py +16 -0
- autocoder/rag/variable_holder.py +4 -2
- autocoder/rags.py +86 -79
- autocoder/regexproject/__init__.py +23 -21
- autocoder/sdk/__init__.py +46 -190
- autocoder/sdk/api.py +370 -0
- autocoder/sdk/async_runner/__init__.py +26 -0
- autocoder/sdk/async_runner/async_executor.py +650 -0
- autocoder/sdk/async_runner/async_handler.py +356 -0
- autocoder/sdk/async_runner/markdown_processor.py +595 -0
- autocoder/sdk/async_runner/task_metadata.py +284 -0
- autocoder/sdk/async_runner/worktree_manager.py +438 -0
- autocoder/sdk/cli/__init__.py +2 -5
- autocoder/sdk/cli/formatters.py +28 -204
- autocoder/sdk/cli/handlers.py +77 -44
- autocoder/sdk/cli/main.py +154 -171
- autocoder/sdk/cli/options.py +95 -22
- autocoder/sdk/constants.py +139 -51
- autocoder/sdk/core/auto_coder_core.py +484 -109
- autocoder/sdk/core/bridge.py +297 -115
- autocoder/sdk/exceptions.py +18 -12
- autocoder/sdk/formatters/__init__.py +19 -0
- autocoder/sdk/formatters/input.py +64 -0
- autocoder/sdk/formatters/output.py +247 -0
- autocoder/sdk/formatters/stream.py +54 -0
- autocoder/sdk/models/__init__.py +6 -5
- autocoder/sdk/models/options.py +55 -18
- autocoder/sdk/utils/formatters.py +27 -195
- autocoder/suffixproject/__init__.py +28 -25
- autocoder/terminal/__init__.py +14 -0
- autocoder/terminal/app.py +454 -0
- autocoder/terminal/args.py +32 -0
- autocoder/terminal/bootstrap.py +178 -0
- autocoder/terminal/command_processor.py +521 -0
- autocoder/terminal/command_registry.py +57 -0
- autocoder/terminal/help.py +97 -0
- autocoder/terminal/tasks/__init__.py +5 -0
- autocoder/terminal/tasks/background.py +77 -0
- autocoder/terminal/tasks/task_event.py +70 -0
- autocoder/terminal/ui/__init__.py +13 -0
- autocoder/terminal/ui/completer.py +268 -0
- autocoder/terminal/ui/keybindings.py +75 -0
- autocoder/terminal/ui/session.py +41 -0
- autocoder/terminal/ui/toolbar.py +64 -0
- autocoder/terminal/utils/__init__.py +13 -0
- autocoder/terminal/utils/errors.py +18 -0
- autocoder/terminal/utils/paths.py +19 -0
- autocoder/terminal/utils/shell.py +43 -0
- autocoder/terminal_v3/__init__.py +10 -0
- autocoder/terminal_v3/app.py +201 -0
- autocoder/terminal_v3/handlers/__init__.py +5 -0
- autocoder/terminal_v3/handlers/command_handler.py +131 -0
- autocoder/terminal_v3/models/__init__.py +6 -0
- autocoder/terminal_v3/models/conversation_buffer.py +214 -0
- autocoder/terminal_v3/models/message.py +50 -0
- autocoder/terminal_v3/models/tool_display.py +247 -0
- autocoder/terminal_v3/ui/__init__.py +7 -0
- autocoder/terminal_v3/ui/keybindings.py +56 -0
- autocoder/terminal_v3/ui/layout.py +141 -0
- autocoder/terminal_v3/ui/styles.py +43 -0
- autocoder/tsproject/__init__.py +23 -23
- autocoder/utils/auto_coder_utils/chat_stream_out.py +1 -1
- autocoder/utils/llms.py +88 -80
- autocoder/utils/math_utils.py +101 -0
- autocoder/utils/model_provider_selector.py +16 -4
- autocoder/utils/operate_config_api.py +33 -5
- autocoder/utils/thread_utils.py +2 -2
- autocoder/version.py +4 -2
- autocoder/workflow_agents/__init__.py +84 -0
- autocoder/workflow_agents/agent.py +143 -0
- autocoder/workflow_agents/exceptions.py +573 -0
- autocoder/workflow_agents/executor.py +489 -0
- autocoder/workflow_agents/loader.py +737 -0
- autocoder/workflow_agents/runner.py +267 -0
- autocoder/workflow_agents/types.py +172 -0
- autocoder/workflow_agents/utils.py +434 -0
- autocoder/workflow_agents/workflow_manager.py +211 -0
- auto_coder-1.0.0.dist-info/METADATA +0 -396
- auto_coder-1.0.0.dist-info/RECORD +0 -442
- auto_coder-1.0.0.dist-info/licenses/LICENSE +0 -201
- autocoder/auto_coder_server.py +0 -672
- autocoder/benchmark.py +0 -138
- autocoder/common/ac_style_command_parser/example.py +0 -7
- autocoder/common/cleaner.py +0 -31
- autocoder/common/command_completer_v2.py +0 -615
- autocoder/common/context_pruner.py +0 -477
- autocoder/common/conversation_pruner.py +0 -132
- autocoder/common/directory_cache/__init__.py +0 -1
- autocoder/common/directory_cache/cache.py +0 -192
- autocoder/common/directory_cache/test_cache.py +0 -190
- autocoder/common/file_checkpoint/examples.py +0 -217
- autocoder/common/llm_friendly_package_example.py +0 -138
- autocoder/common/llm_friendly_package_test.py +0 -63
- autocoder/common/pull_requests/test_module.py +0 -1
- autocoder/common/rulefiles/autocoderrules_utils.py +0 -484
- autocoder/common/text.py +0 -30
- autocoder/common/v2/agent/agentic_edit_tools/list_package_info_tool_resolver.py +0 -42
- autocoder/common/v2/agent/agentic_edit_tools/test_execute_command_tool_resolver.py +0 -70
- autocoder/common/v2/agent/agentic_edit_tools/test_search_files_tool_resolver.py +0 -163
- autocoder/common/v2/agent/agentic_tool_display.py +0 -183
- autocoder/plugins/dynamic_completion_example.py +0 -148
- autocoder/plugins/sample_plugin.py +0 -160
- autocoder/sdk/cli/__main__.py +0 -26
- autocoder/sdk/cli/completion_wrapper.py +0 -38
- autocoder/sdk/cli/install_completion.py +0 -301
- autocoder/sdk/models/messages.py +0 -209
- autocoder/sdk/session/__init__.py +0 -32
- autocoder/sdk/session/session.py +0 -106
- autocoder/sdk/session/session_manager.py +0 -56
- {auto_coder-1.0.0.dist-info → auto_coder-2.0.0.dist-info}/top_level.txt +0 -0
- /autocoder/{sdk/example.py → common/agent_query_queue/__init__.py} +0 -0
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,106 @@ 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
|
+
from autocoder.inner.async_command_handler import AsyncCommandHandler
|
|
94
|
+
from autocoder.inner.queue_command_handler import QueueCommandHandler
|
|
95
|
+
from autocoder.inner.conversation_command_handlers import (
|
|
96
|
+
ConversationNewCommandHandler,
|
|
97
|
+
ConversationResumeCommandHandler,
|
|
98
|
+
ConversationListCommandHandler,
|
|
99
|
+
ConversationRenameCommandHandler,
|
|
100
|
+
ConversationCommandCommandHandler,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
# 对外API,用于第三方集成 auto-coder 使用。
|
|
104
|
+
|
|
73
105
|
|
|
74
|
-
## 对外API,用于第三方集成 auto-coder 使用。
|
|
75
106
|
class SymbolItem(BaseModel):
|
|
76
107
|
symbol_name: str
|
|
77
108
|
symbol_type: SymbolType
|
|
78
109
|
file_name: str
|
|
79
110
|
|
|
111
|
+
|
|
80
112
|
class InitializeSystemRequest(BaseModel):
|
|
81
113
|
product_mode: str
|
|
82
114
|
skip_provider_selection: bool
|
|
@@ -92,20 +124,45 @@ if platform.system() == "Windows":
|
|
|
92
124
|
init()
|
|
93
125
|
|
|
94
126
|
|
|
95
|
-
memory
|
|
96
|
-
"conversation": [],
|
|
97
|
-
"current_files": {"files": [], "groups": {}},
|
|
98
|
-
"conf": {},
|
|
99
|
-
"exclude_dirs": [],
|
|
100
|
-
"mode": "auto_detect", # 新增mode字段,默认为 auto_detect 模式
|
|
101
|
-
}
|
|
102
|
-
|
|
127
|
+
# Initialize memory and project root
|
|
103
128
|
project_root = os.getcwd()
|
|
104
129
|
|
|
130
|
+
# Initialize memory manager with project root
|
|
131
|
+
_memory_manager = get_memory_manager(project_root)
|
|
132
|
+
|
|
133
|
+
# Wrapper functions to sync global memory variable
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def save_memory():
|
|
137
|
+
"""Save memory - compatibility function (no-op since MemoryManager handles persistence)"""
|
|
138
|
+
# This function is kept for backward compatibility but does nothing
|
|
139
|
+
# since MemoryManager automatically handles persistence
|
|
140
|
+
raise NotImplementedError(
|
|
141
|
+
"save_memory is not supported anymore, please use autocoder.common.core_config.memory_manager instead."
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def load_memory():
|
|
146
|
+
"""Load memory using MemoryManager"""
|
|
147
|
+
return _load_memory()
|
|
148
|
+
|
|
105
149
|
|
|
106
|
-
|
|
150
|
+
def get_memory():
|
|
151
|
+
"""Get current memory"""
|
|
152
|
+
return load_memory()
|
|
107
153
|
|
|
108
|
-
|
|
154
|
+
|
|
155
|
+
# Compatibility: base_persist_dir is now managed by memory manager
|
|
156
|
+
base_persist_dir = _memory_manager.base_persist_dir
|
|
157
|
+
|
|
158
|
+
defaut_exclude_dirs = [
|
|
159
|
+
".git",
|
|
160
|
+
"node_modules",
|
|
161
|
+
"dist",
|
|
162
|
+
"build",
|
|
163
|
+
"__pycache__",
|
|
164
|
+
".auto-coder",
|
|
165
|
+
]
|
|
109
166
|
|
|
110
167
|
commands = [
|
|
111
168
|
"/add_files",
|
|
@@ -122,7 +179,7 @@ commands = [
|
|
|
122
179
|
"/index/build",
|
|
123
180
|
"/index/export",
|
|
124
181
|
"/index/import",
|
|
125
|
-
"/exclude_files",
|
|
182
|
+
"/exclude_files",
|
|
126
183
|
"/help",
|
|
127
184
|
"/shell",
|
|
128
185
|
"/voice_input",
|
|
@@ -137,21 +194,65 @@ commands = [
|
|
|
137
194
|
"/conf/export",
|
|
138
195
|
"/conf/import",
|
|
139
196
|
"/exclude_dirs",
|
|
197
|
+
"/queue",
|
|
140
198
|
]
|
|
141
199
|
|
|
200
|
+
|
|
142
201
|
def load_tokenizer():
|
|
143
202
|
from autocoder.rag.variable_holder import VariableHolder
|
|
144
|
-
from tokenizers import Tokenizer
|
|
203
|
+
from tokenizers import Tokenizer
|
|
204
|
+
|
|
145
205
|
try:
|
|
146
|
-
tokenizer_path =
|
|
147
|
-
"autocoder", "data/tokenizer.json"
|
|
148
|
-
)
|
|
206
|
+
tokenizer_path = str(resources.files("autocoder") / "data" / "tokenizer.json")
|
|
149
207
|
VariableHolder.TOKENIZER_PATH = tokenizer_path
|
|
150
208
|
VariableHolder.TOKENIZER_MODEL = Tokenizer.from_file(tokenizer_path)
|
|
151
209
|
except FileNotFoundError:
|
|
152
210
|
tokenizer_path = None
|
|
153
211
|
|
|
154
212
|
|
|
213
|
+
def configure_logger():
|
|
214
|
+
# 设置日志目录和文件
|
|
215
|
+
log_dir = os.path.join(project_root, ".auto-coder", "logs")
|
|
216
|
+
os.makedirs(log_dir, exist_ok=True)
|
|
217
|
+
log_file = os.path.join(log_dir, "auto-coder.log")
|
|
218
|
+
|
|
219
|
+
# 配置全局日志
|
|
220
|
+
# 默认情况下,所有日志都写入文件
|
|
221
|
+
# 控制台上默认不输出任何日志,除非显式配置
|
|
222
|
+
global_logger.configure(
|
|
223
|
+
handlers=[
|
|
224
|
+
{
|
|
225
|
+
"sink": log_file,
|
|
226
|
+
"level": "INFO",
|
|
227
|
+
"rotation": "10 MB",
|
|
228
|
+
"retention": "1 week",
|
|
229
|
+
"format": "{time:YYYY-MM-DD HH:mm:ss} | {level} | {name} | {message}",
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
"sink": sys.stdout,
|
|
233
|
+
"level": "INFO",
|
|
234
|
+
"format": "{time:YYYY-MM-DD HH:mm:ss} | {name} | {message}",
|
|
235
|
+
# 默认不打印任何日志到控制台
|
|
236
|
+
"filter": lambda record: False,
|
|
237
|
+
},
|
|
238
|
+
]
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def init_singleton_instances():
|
|
243
|
+
# 初始化文件监控系统
|
|
244
|
+
try:
|
|
245
|
+
FileMonitor(project_root).start()
|
|
246
|
+
except Exception as e:
|
|
247
|
+
global_logger.error(f"Failed to start file monitor: {e}")
|
|
248
|
+
global_logger.exception(e)
|
|
249
|
+
|
|
250
|
+
# 初始化忽略文件管理器
|
|
251
|
+
from autocoder.common.ignorefiles.ignore_file_utils import IgnoreFileManager
|
|
252
|
+
|
|
253
|
+
_ = IgnoreFileManager(project_root=project_root)
|
|
254
|
+
|
|
255
|
+
|
|
155
256
|
def configure_project_type():
|
|
156
257
|
from prompt_toolkit.lexers import PygmentsLexer
|
|
157
258
|
from pygments.lexers.markup import MarkdownLexer
|
|
@@ -173,12 +274,10 @@ def configure_project_type():
|
|
|
173
274
|
print_formatted_text(HTML(f"<info>{escape(text)}</info>"), style=style)
|
|
174
275
|
|
|
175
276
|
def print_warning(text):
|
|
176
|
-
print_formatted_text(
|
|
177
|
-
HTML(f"<warning>{escape(text)}</warning>"), style=style)
|
|
277
|
+
print_formatted_text(HTML(f"<warning>{escape(text)}</warning>"), style=style)
|
|
178
278
|
|
|
179
279
|
def print_header(text):
|
|
180
|
-
print_formatted_text(
|
|
181
|
-
HTML(f"<header>{escape(text)}</header>"), style=style)
|
|
280
|
+
print_formatted_text(HTML(f"<header>{escape(text)}</header>"), style=style)
|
|
182
281
|
|
|
183
282
|
print_header(f"\n=== {get_message('project_type_config')} ===\n")
|
|
184
283
|
print_info(get_message("project_type_supports"))
|
|
@@ -188,7 +287,7 @@ def configure_project_type():
|
|
|
188
287
|
print_info(get_message("examples"))
|
|
189
288
|
|
|
190
289
|
print_warning(f"{get_message('default_type')}\n")
|
|
191
|
-
|
|
290
|
+
|
|
192
291
|
extensions = get_all_extensions(project_root) or "py"
|
|
193
292
|
project_type = prompt(
|
|
194
293
|
get_message("enter_project_type"), default=extensions, style=style
|
|
@@ -215,72 +314,27 @@ def get_all_extensions(directory: str = ".") -> str:
|
|
|
215
314
|
target_file="",
|
|
216
315
|
git_url="",
|
|
217
316
|
project_type="",
|
|
218
|
-
conversation_prune_safe_zone_tokens=0
|
|
317
|
+
conversation_prune_safe_zone_tokens=0,
|
|
219
318
|
)
|
|
220
|
-
|
|
319
|
+
|
|
221
320
|
analyzer = EnhancedFileAnalyzer(
|
|
222
321
|
args=args,
|
|
223
322
|
llm=None, # 如果只是获取后缀名,可以不需要LLM
|
|
224
|
-
config=None # 使用默认配置
|
|
323
|
+
config=None, # 使用默认配置
|
|
225
324
|
)
|
|
226
|
-
|
|
325
|
+
|
|
227
326
|
# 获取分析结果
|
|
228
327
|
analysis_result = analyzer.analyze_extensions()
|
|
229
|
-
|
|
328
|
+
|
|
230
329
|
# 合并 code 和 config 的后缀名
|
|
231
330
|
all_extensions = set(analysis_result["code"] + analysis_result["config"])
|
|
232
|
-
|
|
331
|
+
|
|
233
332
|
# 转换为逗号分隔的字符串
|
|
234
333
|
return ",".join(sorted(all_extensions))
|
|
235
334
|
|
|
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
335
|
|
|
282
|
-
def start():
|
|
283
|
-
if os.environ.get(
|
|
336
|
+
def start():
|
|
337
|
+
if os.environ.get("autocoder_auto_init", "true") in ["true", "True", "True", True]:
|
|
284
338
|
configure_logger()
|
|
285
339
|
init_singleton_instances()
|
|
286
340
|
|
|
@@ -292,7 +346,7 @@ def start():
|
|
|
292
346
|
# name = f"{time_str}-{str(uuid.uuid4())}"
|
|
293
347
|
# conversation_id = conversation_manager.create_new_conversation(name=name,description="")
|
|
294
348
|
# conversation_manager.set_current_conversation(conversation_id)
|
|
295
|
-
|
|
349
|
+
|
|
296
350
|
|
|
297
351
|
def stop():
|
|
298
352
|
try:
|
|
@@ -301,9 +355,11 @@ def stop():
|
|
|
301
355
|
global_logger.error(f"Failed to stop file monitor: {e}")
|
|
302
356
|
global_logger.exception(e)
|
|
303
357
|
|
|
304
|
-
|
|
358
|
+
|
|
359
|
+
def initialize_system(args: InitializeSystemRequest):
|
|
305
360
|
from autocoder.utils.model_provider_selector import ModelProviderSelector
|
|
306
|
-
from autocoder import
|
|
361
|
+
from autocoder.common.llms import LLMManager
|
|
362
|
+
|
|
307
363
|
print(f"\n\033[1;34m{get_message('initializing')}\033[0m")
|
|
308
364
|
|
|
309
365
|
first_time = [False]
|
|
@@ -319,54 +375,42 @@ def initialize_system(args:InitializeSystemRequest):
|
|
|
319
375
|
else:
|
|
320
376
|
print(f" {message}")
|
|
321
377
|
|
|
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
378
|
if not os.path.exists(base_persist_dir):
|
|
343
379
|
os.makedirs(base_persist_dir, exist_ok=True)
|
|
344
|
-
print_status(
|
|
380
|
+
print_status(
|
|
381
|
+
get_message_with_format("created_dir", path=base_persist_dir), "success"
|
|
382
|
+
)
|
|
345
383
|
|
|
346
384
|
if first_time[0]:
|
|
347
|
-
|
|
385
|
+
configure("project_type:*", skip_print=True)
|
|
348
386
|
configure_success[0] = True
|
|
349
387
|
|
|
350
388
|
print_status(get_message("init_complete"), "success")
|
|
351
389
|
|
|
352
|
-
|
|
390
|
+
init_project_if_required(target_dir=project_root, project_type="*")
|
|
353
391
|
|
|
354
392
|
if not args.skip_provider_selection and first_time[0]:
|
|
355
|
-
if args.product_mode == "lite":
|
|
356
|
-
|
|
393
|
+
if args.product_mode == "lite":
|
|
394
|
+
# 如果已经是配置过的项目,就无需再选择
|
|
357
395
|
if first_time[0]:
|
|
358
|
-
|
|
396
|
+
llm_manager = LLMManager()
|
|
397
|
+
if not llm_manager.check_model_exists(
|
|
398
|
+
"v3_chat"
|
|
399
|
+
) or not llm_manager.check_model_exists("r1_chat"):
|
|
359
400
|
model_provider_selector = ModelProviderSelector()
|
|
360
401
|
model_provider_info = model_provider_selector.select_provider()
|
|
361
402
|
if model_provider_info is not None:
|
|
362
|
-
models_json_list = model_provider_selector.to_models_json(
|
|
363
|
-
|
|
403
|
+
models_json_list = model_provider_selector.to_models_json(
|
|
404
|
+
model_provider_info
|
|
405
|
+
)
|
|
406
|
+
llm_manager.add_models(models_json_list)
|
|
364
407
|
|
|
365
408
|
if args.product_mode == "pro":
|
|
366
409
|
# Check if Ray is running
|
|
367
410
|
print_status(get_message("checking_ray"), "")
|
|
368
411
|
ray_status = subprocess.run(
|
|
369
|
-
["ray", "status"], capture_output=True, text=True
|
|
412
|
+
["ray", "status"], capture_output=True, text=True
|
|
413
|
+
)
|
|
370
414
|
if ray_status.returncode != 0:
|
|
371
415
|
print_status(get_message("ray_not_running"), "warning")
|
|
372
416
|
try:
|
|
@@ -389,7 +433,6 @@ def initialize_system(args:InitializeSystemRequest):
|
|
|
389
433
|
)
|
|
390
434
|
if result.returncode == 0:
|
|
391
435
|
print_status(get_message("model_available"), "success")
|
|
392
|
-
init_project()
|
|
393
436
|
print_status(get_message("init_complete_final"), "success")
|
|
394
437
|
return
|
|
395
438
|
except subprocess.TimeoutExpired:
|
|
@@ -428,7 +471,6 @@ def initialize_system(args:InitializeSystemRequest):
|
|
|
428
471
|
print_status(get_message("deploy_fail"), "error")
|
|
429
472
|
return
|
|
430
473
|
|
|
431
|
-
|
|
432
474
|
deploy_cmd = [
|
|
433
475
|
"byzerllm",
|
|
434
476
|
"deploy",
|
|
@@ -471,14 +513,18 @@ def initialize_system(args:InitializeSystemRequest):
|
|
|
471
513
|
print_status(get_message("manual_start"), "warning")
|
|
472
514
|
print_status("easy-byzerllm chat v3_chat 你好", "")
|
|
473
515
|
|
|
474
|
-
print_status(get_message("init_complete_final"), "success")
|
|
516
|
+
print_status(get_message("init_complete_final"), "success")
|
|
475
517
|
configure_success[0] = True
|
|
476
518
|
|
|
477
519
|
if first_time[0] and args.product_mode == "pro" and configure_success[0]:
|
|
478
|
-
configure(f"model:v3_chat", skip_print=True)
|
|
520
|
+
configure(f"model:v3_chat", skip_print=True)
|
|
479
521
|
|
|
480
|
-
if
|
|
481
|
-
|
|
522
|
+
if (
|
|
523
|
+
first_time[0]
|
|
524
|
+
and args.product_mode == "lite"
|
|
525
|
+
and LLMManager().check_model_exists("v3_chat")
|
|
526
|
+
):
|
|
527
|
+
configure(f"model:v3_chat", skip_print=True)
|
|
482
528
|
|
|
483
529
|
|
|
484
530
|
def convert_yaml_config_to_str(yaml_config):
|
|
@@ -491,92 +537,44 @@ def convert_yaml_config_to_str(yaml_config):
|
|
|
491
537
|
return yaml_content
|
|
492
538
|
|
|
493
539
|
|
|
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
540
|
def convert_config_value(key, value):
|
|
541
|
+
# 定义需要使用 token 解析的字段
|
|
542
|
+
token_fields = {
|
|
543
|
+
"conversation_prune_safe_zone_tokens",
|
|
544
|
+
"context_prune_safe_zone_tokens",
|
|
545
|
+
"context_prune_sliding_window_size",
|
|
546
|
+
"context_prune_sliding_window_overlap",
|
|
547
|
+
"rag_params_max_tokens",
|
|
548
|
+
"rag_context_window_limit",
|
|
549
|
+
"rag_duckdb_vector_dim",
|
|
550
|
+
"rag_duckdb_query_top_k",
|
|
551
|
+
"rag_emb_dim",
|
|
552
|
+
"rag_emb_text_size",
|
|
553
|
+
"hybrid_index_max_output_tokens",
|
|
554
|
+
"data_cells_max_num",
|
|
555
|
+
}
|
|
556
|
+
|
|
572
557
|
field_info = AutoCoderArgs.model_fields.get(key)
|
|
573
558
|
if field_info:
|
|
559
|
+
# 对于需要 token 解析的字段,使用 AutoCoderArgsParser
|
|
560
|
+
if key in token_fields:
|
|
561
|
+
try:
|
|
562
|
+
parser = AutoCoderArgsParser()
|
|
563
|
+
return parser.parse_token_field(key, value)
|
|
564
|
+
except Exception as e:
|
|
565
|
+
print(
|
|
566
|
+
f"Warning: Failed to parse token field '{key}' with value '{value}': {e}"
|
|
567
|
+
)
|
|
568
|
+
# 如果解析失败,fallback 到原有逻辑
|
|
569
|
+
pass
|
|
570
|
+
|
|
571
|
+
# 原有的类型转换逻辑
|
|
574
572
|
if isinstance(value, str) and value.lower() in ["true", "false"]:
|
|
575
573
|
return value.lower() == "true"
|
|
576
|
-
elif "int" in str(field_info.annotation):
|
|
577
|
-
return int(value)
|
|
578
574
|
elif "float" in str(field_info.annotation):
|
|
579
575
|
return float(value)
|
|
576
|
+
elif "int" in str(field_info.annotation):
|
|
577
|
+
return int(value)
|
|
580
578
|
else:
|
|
581
579
|
return value
|
|
582
580
|
else:
|
|
@@ -594,14 +592,14 @@ def redirect_stdout():
|
|
|
594
592
|
sys.stdout = original_stdout
|
|
595
593
|
|
|
596
594
|
|
|
597
|
-
def configure(conf: str, skip_print=
|
|
595
|
+
def configure(conf: str, skip_print=True):
|
|
598
596
|
printer = Printer()
|
|
597
|
+
memory_manager = get_memory_manager()
|
|
599
598
|
parts = conf.split(None, 1)
|
|
600
599
|
if len(parts) == 2 and parts[0] in ["/drop", "/unset", "/remove"]:
|
|
601
600
|
key = parts[1].strip()
|
|
602
|
-
if key
|
|
603
|
-
|
|
604
|
-
save_memory()
|
|
601
|
+
if memory_manager.has_config(key):
|
|
602
|
+
memory_manager.delete_config(key)
|
|
605
603
|
printer.print_in_terminal("config_delete_success", style="green", key=key)
|
|
606
604
|
else:
|
|
607
605
|
printer.print_in_terminal("config_not_found", style="yellow", key=key)
|
|
@@ -616,109 +614,75 @@ def configure(conf: str, skip_print=False):
|
|
|
616
614
|
if not value:
|
|
617
615
|
printer.print_in_terminal("config_value_empty", style="red")
|
|
618
616
|
return
|
|
619
|
-
product_mode =
|
|
617
|
+
product_mode = memory_manager.get_config("product_mode", None)
|
|
620
618
|
if product_mode:
|
|
621
|
-
ConfigValidator.validate(key, value, product_mode)
|
|
622
|
-
|
|
623
|
-
save_memory()
|
|
619
|
+
ConfigValidator.validate(key, value, product_mode)
|
|
620
|
+
memory_manager.set_config(key, value)
|
|
624
621
|
if not skip_print:
|
|
625
|
-
printer.print_in_terminal(
|
|
622
|
+
printer.print_in_terminal(
|
|
623
|
+
"config_set_success", style="green", key=key, value=value
|
|
624
|
+
)
|
|
625
|
+
|
|
626
626
|
|
|
627
627
|
# word_completer = WordCompleter(commands)
|
|
628
628
|
|
|
629
629
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
630
|
+
# Memory management functions are now imported from core_config module
|
|
631
|
+
# Helper functions to access memory without global variables
|
|
632
|
+
def get_current_memory():
|
|
633
|
+
"""Get current memory as dictionary for backward compatibility"""
|
|
634
|
+
return get_memory()
|
|
633
635
|
|
|
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
|
-
|
|
636
|
+
|
|
637
|
+
def get_current_files():
|
|
638
|
+
"""Get current files list"""
|
|
639
|
+
memory_manager = get_memory_manager()
|
|
640
|
+
return memory_manager.get_current_files()
|
|
641
|
+
|
|
642
|
+
|
|
643
|
+
def set_current_files(files):
|
|
644
|
+
"""Set current files list"""
|
|
645
|
+
memory_manager = get_memory_manager()
|
|
646
|
+
memory_manager.set_current_files(files)
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
def get_file_groups():
|
|
650
|
+
"""Get file groups"""
|
|
651
|
+
memory_manager = get_memory_manager()
|
|
652
|
+
return memory_manager.get_file_groups()
|
|
653
|
+
|
|
654
|
+
|
|
655
|
+
def get_exclude_dirs():
|
|
656
|
+
"""Get exclude directories"""
|
|
657
|
+
memory_manager = get_memory_manager()
|
|
658
|
+
return memory_manager.get_exclude_dirs()
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
# 使用 project_scanner 模块创建兼容函数(供其他地方使用)
|
|
662
|
+
scanner_funcs = create_scanner_functions(
|
|
663
|
+
project_root=project_root,
|
|
664
|
+
default_exclude_dirs=defaut_exclude_dirs,
|
|
665
|
+
get_extra_exclude_dirs_func=get_exclude_dirs,
|
|
666
|
+
)
|
|
667
|
+
|
|
668
|
+
# 导出兼容函数
|
|
669
|
+
get_all_file_names_in_project = scanner_funcs["get_all_file_names_in_project"]
|
|
670
|
+
get_all_file_in_project = scanner_funcs["get_all_file_in_project"]
|
|
671
|
+
get_all_file_in_project_with_dot = scanner_funcs["get_all_file_in_project_with_dot"]
|
|
672
|
+
get_all_dir_names_in_project = scanner_funcs["get_all_dir_names_in_project"]
|
|
673
|
+
find_files_in_project = scanner_funcs["find_files_in_project"]
|
|
674
|
+
get_symbol_list = scanner_funcs["get_symbol_list"]
|
|
675
|
+
|
|
676
|
+
# 直接创建 CommandCompleterV2,它内部会使用 project_scanner
|
|
677
|
+
completer = CommandCompleterV2(
|
|
678
|
+
commands,
|
|
679
|
+
memory_model=CCMemoryModel(
|
|
680
|
+
get_memory_func=get_memory, save_memory_func=save_memory
|
|
681
|
+
),
|
|
682
|
+
project_root=project_root,
|
|
683
|
+
)
|
|
669
684
|
|
|
670
685
|
|
|
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
686
|
def revert():
|
|
723
687
|
result_manager = ResultManager()
|
|
724
688
|
last_yaml_file = get_last_yaml_file("actions")
|
|
@@ -728,57 +692,36 @@ def revert():
|
|
|
728
692
|
with redirect_stdout() as output:
|
|
729
693
|
auto_coder_main(["revert", "--file", file_path])
|
|
730
694
|
s = output.getvalue()
|
|
731
|
-
|
|
695
|
+
|
|
732
696
|
console = Console()
|
|
733
697
|
panel = Panel(
|
|
734
698
|
Markdown(s),
|
|
735
699
|
title="Revert Result",
|
|
736
700
|
border_style="green" if "Successfully reverted changes" in s else "red",
|
|
737
701
|
padding=(1, 2),
|
|
738
|
-
expand=False
|
|
702
|
+
expand=False,
|
|
739
703
|
)
|
|
740
704
|
console.print(panel)
|
|
741
|
-
|
|
705
|
+
|
|
742
706
|
if "Successfully reverted changes" in s:
|
|
743
|
-
result_manager.append(
|
|
744
|
-
|
|
707
|
+
result_manager.append(
|
|
708
|
+
content=s, meta={"action": "revert", "success": False, "input": {}}
|
|
709
|
+
)
|
|
745
710
|
else:
|
|
746
|
-
result_manager.append(
|
|
747
|
-
|
|
711
|
+
result_manager.append(
|
|
712
|
+
content=s, meta={"action": "revert", "success": False, "input": {}}
|
|
713
|
+
)
|
|
748
714
|
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()
|
|
715
|
+
result_manager.append(
|
|
716
|
+
content="No previous chat action found to revert.",
|
|
717
|
+
meta={"action": "revert", "success": False, "input": {}},
|
|
718
|
+
)
|
|
776
719
|
|
|
777
720
|
|
|
778
721
|
def _handle_post_commit_and_pr(post_commit: bool, pr: bool, query: str, args, llm):
|
|
779
722
|
"""
|
|
780
723
|
处理 post_commit 和 PR 功能
|
|
781
|
-
|
|
724
|
+
|
|
782
725
|
Args:
|
|
783
726
|
post_commit: 是否执行 post_commit
|
|
784
727
|
pr: 是否创建 PR
|
|
@@ -787,13 +730,11 @@ def _handle_post_commit_and_pr(post_commit: bool, pr: bool, query: str, args, ll
|
|
|
787
730
|
llm: LLM 实例
|
|
788
731
|
"""
|
|
789
732
|
printer = Printer()
|
|
790
|
-
console = Console()
|
|
791
|
-
|
|
792
733
|
try:
|
|
793
734
|
if post_commit:
|
|
794
735
|
# 执行 post_commit 操作
|
|
795
736
|
printer.print_in_terminal("post_commit_executing", style="blue")
|
|
796
|
-
|
|
737
|
+
|
|
797
738
|
# 检查是否有未提交的更改
|
|
798
739
|
uncommitted_changes = git_utils.get_uncommitted_changes(".")
|
|
799
740
|
if uncommitted_changes:
|
|
@@ -801,102 +742,120 @@ def _handle_post_commit_and_pr(post_commit: bool, pr: bool, query: str, args, ll
|
|
|
801
742
|
commit_message = git_utils.generate_commit_message.with_llm(llm).run(
|
|
802
743
|
uncommitted_changes
|
|
803
744
|
)
|
|
804
|
-
|
|
745
|
+
|
|
805
746
|
# 执行提交
|
|
806
747
|
commit_result = git_utils.commit_changes(".", commit_message)
|
|
807
748
|
git_utils.print_commit_info(commit_result=commit_result)
|
|
808
|
-
printer.print_in_terminal(
|
|
809
|
-
|
|
749
|
+
printer.print_in_terminal(
|
|
750
|
+
"post_commit_success", style="green", message=commit_message
|
|
751
|
+
)
|
|
752
|
+
|
|
810
753
|
# 如果需要创建 PR,则继续处理
|
|
811
754
|
if pr:
|
|
812
755
|
_create_pull_request(commit_result, query, llm)
|
|
813
756
|
else:
|
|
814
757
|
printer.print_in_terminal("post_commit_no_changes", style="yellow")
|
|
815
|
-
|
|
758
|
+
|
|
816
759
|
elif pr:
|
|
817
760
|
# 只创建 PR,不执行 post_commit
|
|
818
761
|
# 获取最后一个 commit
|
|
819
762
|
try:
|
|
820
763
|
repo = git.Repo(".")
|
|
821
764
|
last_commit = repo.head.commit
|
|
822
|
-
|
|
765
|
+
|
|
823
766
|
# 创建一个模拟的 commit_result 对象
|
|
824
767
|
class MockCommitResult:
|
|
825
768
|
def __init__(self, commit):
|
|
826
769
|
self.commit_hash = commit.hexsha
|
|
827
770
|
self.commit_message = commit.message.strip()
|
|
828
771
|
self.changed_files = []
|
|
829
|
-
|
|
772
|
+
|
|
830
773
|
mock_commit_result = MockCommitResult(last_commit)
|
|
831
774
|
_create_pull_request(mock_commit_result, query, llm)
|
|
832
|
-
|
|
775
|
+
|
|
833
776
|
except Exception as e:
|
|
834
|
-
printer.print_in_terminal(
|
|
835
|
-
|
|
777
|
+
printer.print_in_terminal(
|
|
778
|
+
"pr_get_last_commit_failed", style="red", error=str(e)
|
|
779
|
+
)
|
|
780
|
+
|
|
836
781
|
except Exception as e:
|
|
837
782
|
printer.print_in_terminal("post_commit_pr_failed", style="red", error=str(e))
|
|
838
783
|
|
|
839
|
-
|
|
784
|
+
|
|
785
|
+
def init_project_if_required(target_dir: str, project_type: str):
|
|
840
786
|
"""
|
|
841
787
|
如果项目没有初始化,则自动初始化项目
|
|
842
|
-
|
|
788
|
+
|
|
843
789
|
Args:
|
|
844
790
|
target_dir: 目标目录路径
|
|
845
|
-
"""
|
|
846
|
-
|
|
791
|
+
"""
|
|
792
|
+
|
|
847
793
|
# 确保目标目录是绝对路径
|
|
848
794
|
if not os.path.isabs(target_dir):
|
|
849
795
|
target_dir = os.path.abspath(target_dir)
|
|
850
|
-
|
|
796
|
+
|
|
851
797
|
actions_dir = os.path.join(target_dir, "actions")
|
|
852
798
|
auto_coder_dir = os.path.join(target_dir, ".auto-coder")
|
|
853
|
-
|
|
799
|
+
|
|
854
800
|
# 检查是否已经初始化
|
|
855
801
|
if os.path.exists(actions_dir) and os.path.exists(auto_coder_dir):
|
|
856
802
|
return # 已经初始化,无需再次初始化
|
|
857
|
-
|
|
803
|
+
|
|
858
804
|
printer = Printer()
|
|
859
|
-
|
|
860
|
-
try:
|
|
805
|
+
|
|
806
|
+
try:
|
|
861
807
|
# 创建必要的目录
|
|
862
808
|
os.makedirs(actions_dir, exist_ok=True)
|
|
863
809
|
os.makedirs(auto_coder_dir, exist_ok=True)
|
|
864
|
-
|
|
810
|
+
|
|
865
811
|
# 导入并使用 create_actions 创建默认的 action 文件
|
|
866
812
|
from autocoder.common.command_templates import create_actions
|
|
867
|
-
|
|
813
|
+
|
|
868
814
|
create_actions(
|
|
869
815
|
source_dir=target_dir,
|
|
870
|
-
params={
|
|
871
|
-
"project_type": project_type,
|
|
872
|
-
"source_dir": target_dir
|
|
873
|
-
},
|
|
816
|
+
params={"project_type": project_type, "source_dir": target_dir},
|
|
874
817
|
)
|
|
875
|
-
|
|
818
|
+
|
|
876
819
|
# 初始化 git 仓库
|
|
877
820
|
try:
|
|
878
821
|
git_utils.init(target_dir)
|
|
879
822
|
except Exception as e:
|
|
880
823
|
global_logger.warning(f"Failed to initialize git repository: {e}")
|
|
881
|
-
|
|
824
|
+
|
|
882
825
|
# 创建或更新 .gitignore 文件
|
|
883
826
|
gitignore_path = os.path.join(target_dir, ".gitignore")
|
|
884
|
-
gitignore_entries = [
|
|
885
|
-
|
|
827
|
+
gitignore_entries = [
|
|
828
|
+
".auto-coder/",
|
|
829
|
+
"/actions/",
|
|
830
|
+
"/output.txt",
|
|
831
|
+
".autocoderrules",
|
|
832
|
+
".autocodertools",
|
|
833
|
+
".autocodercommands",
|
|
834
|
+
".autocoderagents",
|
|
835
|
+
".autocoderlinters",
|
|
836
|
+
]
|
|
837
|
+
|
|
886
838
|
try:
|
|
887
|
-
#
|
|
888
|
-
|
|
839
|
+
# 读取现有的 .gitignore 内容
|
|
840
|
+
existing_entries = set()
|
|
889
841
|
if os.path.exists(gitignore_path):
|
|
890
842
|
with open(gitignore_path, "r", encoding="utf-8") as f:
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
843
|
+
# 将现有内容按行分割并去除空白字符,转换为集合以便快速查找
|
|
844
|
+
existing_entries = {line.strip() for line in f if line.strip()}
|
|
845
|
+
|
|
846
|
+
# 筛选出需要添加的新条目
|
|
847
|
+
new_entries = [
|
|
848
|
+
entry for entry in gitignore_entries if entry not in existing_entries
|
|
849
|
+
]
|
|
850
|
+
|
|
851
|
+
# 如果有新条目需要添加,则写入文件
|
|
852
|
+
if new_entries:
|
|
853
|
+
with open(gitignore_path, "a", encoding="utf-8") as f:
|
|
854
|
+
for entry in new_entries:
|
|
855
|
+
f.write(f"\n{entry}")
|
|
897
856
|
except Exception as e:
|
|
898
857
|
global_logger.warning(f"Failed to update .gitignore: {e}")
|
|
899
|
-
|
|
858
|
+
|
|
900
859
|
# 创建 .autocoderignore 文件
|
|
901
860
|
try:
|
|
902
861
|
autocoderignore_path = os.path.join(target_dir, ".autocoderignore")
|
|
@@ -907,9 +866,11 @@ def init_project_if_required(target_dir: str,project_type:str):
|
|
|
907
866
|
except Exception as e:
|
|
908
867
|
global_logger.warning(f"Failed to create .autocoderignore: {e}")
|
|
909
868
|
|
|
910
|
-
configure(f"project_type:{project_type}")
|
|
911
|
-
global_logger.info(
|
|
912
|
-
|
|
869
|
+
configure(f"project_type:{project_type}", skip_print=True)
|
|
870
|
+
global_logger.info(
|
|
871
|
+
f"Successfully initialized auto-coder project in {target_dir}"
|
|
872
|
+
)
|
|
873
|
+
|
|
913
874
|
except Exception as e:
|
|
914
875
|
global_logger.error(f"Failed to initialize project in {target_dir}: {e}")
|
|
915
876
|
printer.print_in_terminal("init_project_error", style="red", error=str(e))
|
|
@@ -918,7 +879,7 @@ def init_project_if_required(target_dir: str,project_type:str):
|
|
|
918
879
|
def _create_pull_request(commit_result, original_query: str, llm):
|
|
919
880
|
"""
|
|
920
881
|
创建 Pull Request
|
|
921
|
-
|
|
882
|
+
|
|
922
883
|
Args:
|
|
923
884
|
commit_result: 提交结果对象
|
|
924
885
|
original_query: 原始查询
|
|
@@ -926,76 +887,92 @@ def _create_pull_request(commit_result, original_query: str, llm):
|
|
|
926
887
|
"""
|
|
927
888
|
printer = Printer()
|
|
928
889
|
console = Console()
|
|
929
|
-
|
|
890
|
+
|
|
930
891
|
try:
|
|
931
892
|
# 检查是否安装了 gh CLI
|
|
932
893
|
gh_check = subprocess.run(["gh", "--version"], capture_output=True, text=True)
|
|
933
894
|
if gh_check.returncode != 0:
|
|
934
895
|
printer.print_in_terminal("pr_gh_not_installed", style="red")
|
|
935
896
|
return
|
|
936
|
-
|
|
897
|
+
|
|
937
898
|
# 检查是否已经登录 GitHub
|
|
938
|
-
auth_check = subprocess.run(
|
|
899
|
+
auth_check = subprocess.run(
|
|
900
|
+
["gh", "auth", "status"], capture_output=True, text=True
|
|
901
|
+
)
|
|
939
902
|
if auth_check.returncode != 0:
|
|
940
903
|
printer.print_in_terminal("pr_gh_not_authenticated", style="red")
|
|
941
904
|
return
|
|
942
|
-
|
|
905
|
+
|
|
943
906
|
# 获取当前分支名
|
|
944
907
|
repo = git.Repo(".")
|
|
945
908
|
current_branch = repo.active_branch.name
|
|
946
|
-
|
|
909
|
+
|
|
947
910
|
# 如果在 main/master 分支,创建新分支
|
|
948
911
|
if current_branch in ["main", "master"]:
|
|
949
912
|
# 生成新分支名
|
|
950
913
|
import re
|
|
951
|
-
|
|
914
|
+
|
|
915
|
+
branch_name = re.sub(r"[^a-zA-Z0-9\-_]", "-", original_query.lower())
|
|
952
916
|
branch_name = f"auto-coder-{branch_name[:30]}-{int(time.time())}"
|
|
953
|
-
|
|
917
|
+
|
|
954
918
|
# 创建并切换到新分支
|
|
955
919
|
new_branch = repo.create_head(branch_name)
|
|
956
920
|
new_branch.checkout()
|
|
957
921
|
current_branch = branch_name
|
|
958
|
-
|
|
959
|
-
printer.print_in_terminal(
|
|
960
|
-
|
|
922
|
+
|
|
923
|
+
printer.print_in_terminal(
|
|
924
|
+
"pr_created_branch", style="blue", branch=branch_name
|
|
925
|
+
)
|
|
926
|
+
|
|
961
927
|
# 推送当前分支到远程
|
|
962
928
|
try:
|
|
963
929
|
origin = repo.remotes.origin
|
|
964
930
|
origin.push(current_branch)
|
|
965
|
-
printer.print_in_terminal(
|
|
931
|
+
printer.print_in_terminal(
|
|
932
|
+
"pr_pushed_branch", style="blue", branch=current_branch
|
|
933
|
+
)
|
|
966
934
|
except Exception as e:
|
|
967
935
|
printer.print_in_terminal("pr_push_failed", style="red", error=str(e))
|
|
968
936
|
return
|
|
969
|
-
|
|
937
|
+
|
|
970
938
|
# 生成 PR 标题和描述
|
|
971
939
|
pr_title, pr_body = _generate_pr_content(commit_result, original_query, llm)
|
|
972
|
-
|
|
940
|
+
|
|
973
941
|
# 创建 PR
|
|
974
942
|
pr_cmd = [
|
|
975
|
-
"gh",
|
|
976
|
-
"
|
|
977
|
-
"
|
|
978
|
-
"--
|
|
943
|
+
"gh",
|
|
944
|
+
"pr",
|
|
945
|
+
"create",
|
|
946
|
+
"--title",
|
|
947
|
+
pr_title,
|
|
948
|
+
"--body",
|
|
949
|
+
pr_body,
|
|
950
|
+
"--head",
|
|
951
|
+
current_branch,
|
|
979
952
|
]
|
|
980
|
-
|
|
953
|
+
|
|
981
954
|
pr_result = subprocess.run(pr_cmd, capture_output=True, text=True)
|
|
982
|
-
|
|
955
|
+
|
|
983
956
|
if pr_result.returncode == 0:
|
|
984
957
|
pr_url = pr_result.stdout.strip()
|
|
985
958
|
printer.print_in_terminal("pr_created_success", style="green", url=pr_url)
|
|
986
|
-
|
|
959
|
+
|
|
987
960
|
# 显示 PR 信息
|
|
988
|
-
console.print(
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
961
|
+
console.print(
|
|
962
|
+
Panel(
|
|
963
|
+
f"[bold green]Pull Request Created Successfully![/bold green]\n\n"
|
|
964
|
+
f"[bold]Title:[/bold] {pr_title}\n"
|
|
965
|
+
f"[bold]URL:[/bold] {pr_url}\n"
|
|
966
|
+
f"[bold]Branch:[/bold] {current_branch}",
|
|
967
|
+
title="🎉 Pull Request",
|
|
968
|
+
border_style="green",
|
|
969
|
+
)
|
|
970
|
+
)
|
|
996
971
|
else:
|
|
997
|
-
printer.print_in_terminal(
|
|
998
|
-
|
|
972
|
+
printer.print_in_terminal(
|
|
973
|
+
"pr_creation_failed", style="red", error=pr_result.stderr
|
|
974
|
+
)
|
|
975
|
+
|
|
999
976
|
except Exception as e:
|
|
1000
977
|
printer.print_in_terminal("pr_creation_error", style="red", error=str(e))
|
|
1001
978
|
|
|
@@ -1004,22 +981,22 @@ def _create_pull_request(commit_result, original_query: str, llm):
|
|
|
1004
981
|
def _generate_pr_content(commit_result, original_query: str, llm) -> tuple:
|
|
1005
982
|
"""
|
|
1006
983
|
生成 PR 标题和描述
|
|
1007
|
-
|
|
984
|
+
|
|
1008
985
|
根据提交信息和原始查询生成合适的 PR 标题和描述。
|
|
1009
|
-
|
|
986
|
+
|
|
1010
987
|
Args:
|
|
1011
988
|
commit_result: 提交结果,包含 commit_message 和 changed_files
|
|
1012
989
|
original_query: 用户的原始查询请求
|
|
1013
|
-
|
|
990
|
+
|
|
1014
991
|
Returns:
|
|
1015
992
|
tuple: (pr_title, pr_body) PR标题和描述内容
|
|
1016
|
-
|
|
993
|
+
|
|
1017
994
|
请生成简洁明了的 PR 标题(不超过72字符)和详细的描述内容。
|
|
1018
995
|
标题应该概括主要变更,描述应该包含:
|
|
1019
996
|
1. 变更的背景和目的
|
|
1020
997
|
2. 主要修改内容
|
|
1021
998
|
3. 影响的文件(如果有的话)
|
|
1022
|
-
|
|
999
|
+
|
|
1023
1000
|
提交信息:{{ commit_result.commit_message }}
|
|
1024
1001
|
原始需求:{{ original_query }}
|
|
1025
1002
|
{% if commit_result.changed_files %}
|
|
@@ -1029,7 +1006,7 @@ def _generate_pr_content(commit_result, original_query: str, llm) -> tuple:
|
|
|
1029
1006
|
{% endfor %}
|
|
1030
1007
|
{% endif %}
|
|
1031
1008
|
"""
|
|
1032
|
-
|
|
1009
|
+
|
|
1033
1010
|
# 这个函数会被 byzerllm 装饰器处理,返回 LLM 生成的内容
|
|
1034
1011
|
# 实际实现会在运行时由装饰器处理
|
|
1035
1012
|
pass
|
|
@@ -1057,14 +1034,14 @@ def _generate_pr_content(commit_result, original_query: str, llm):
|
|
|
1057
1034
|
TITLE: [标题内容]
|
|
1058
1035
|
BODY: [描述内容]
|
|
1059
1036
|
"""
|
|
1060
|
-
|
|
1037
|
+
|
|
1061
1038
|
response = llm.chat([{"role": "user", "content": prompt}])
|
|
1062
|
-
|
|
1039
|
+
|
|
1063
1040
|
# 解析响应
|
|
1064
|
-
lines = response.split(
|
|
1041
|
+
lines = response.split("\n")
|
|
1065
1042
|
title = ""
|
|
1066
1043
|
body = ""
|
|
1067
|
-
|
|
1044
|
+
|
|
1068
1045
|
for line in lines:
|
|
1069
1046
|
if line.startswith("TITLE:"):
|
|
1070
1047
|
title = line.replace("TITLE:", "").strip()
|
|
@@ -1072,15 +1049,15 @@ BODY: [描述内容]
|
|
|
1072
1049
|
body = line.replace("BODY:", "").strip()
|
|
1073
1050
|
elif body: # 如果已经开始收集 body,继续添加后续行
|
|
1074
1051
|
body += "\n" + line
|
|
1075
|
-
|
|
1052
|
+
|
|
1076
1053
|
# 如果解析失败,使用默认值
|
|
1077
1054
|
if not title:
|
|
1078
1055
|
title = f"Auto-coder: {original_query[:50]}..."
|
|
1079
1056
|
if not body:
|
|
1080
1057
|
body = f"This PR was automatically generated by Auto-coder.\n\nOriginal request: {original_query}"
|
|
1081
|
-
|
|
1058
|
+
|
|
1082
1059
|
return title, body
|
|
1083
|
-
|
|
1060
|
+
|
|
1084
1061
|
except Exception as e:
|
|
1085
1062
|
# 如果 LLM 生成失败,使用默认值
|
|
1086
1063
|
title = f"Auto-coder: {original_query[:50]}..."
|
|
@@ -1089,351 +1066,34 @@ BODY: [描述内容]
|
|
|
1089
1066
|
|
|
1090
1067
|
|
|
1091
1068
|
def add_files(args: List[str]):
|
|
1069
|
+
"""
|
|
1070
|
+
处理文件添加命令,使用 AddFilesHandler 进行统一处理
|
|
1092
1071
|
|
|
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}})
|
|
1072
|
+
Args:
|
|
1073
|
+
args: 命令参数列表
|
|
1074
|
+
"""
|
|
1075
|
+
from autocoder.common.file_handler import AddFilesHandler
|
|
1364
1076
|
|
|
1365
|
-
|
|
1077
|
+
handler = AddFilesHandler()
|
|
1078
|
+
handler.handle_add_files_command(args)
|
|
1366
1079
|
|
|
1367
1080
|
|
|
1368
1081
|
def remove_files(file_names: List[str]):
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
result_manager = ResultManager()
|
|
1082
|
+
"""
|
|
1083
|
+
处理文件删除命令,使用 RemoveFilesHandler 进行统一处理
|
|
1372
1084
|
|
|
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
|
-
]
|
|
1085
|
+
Args:
|
|
1086
|
+
file_names: 文件名列表或模式列表
|
|
1087
|
+
"""
|
|
1088
|
+
from autocoder.common.file_handler import RemoveFilesHandler
|
|
1413
1089
|
|
|
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))
|
|
1090
|
+
handler = RemoveFilesHandler()
|
|
1091
|
+
handler.handle_remove_files_command(file_names)
|
|
1421
1092
|
|
|
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
1093
|
|
|
1434
|
-
@run_in_raw_thread()
|
|
1435
1094
|
def ask(query: str):
|
|
1436
|
-
|
|
1095
|
+
memory_manager = get_memory_manager()
|
|
1096
|
+
conf = memory_manager.get_all_config()
|
|
1437
1097
|
yaml_config = {
|
|
1438
1098
|
"include_file": ["./base/base.yml"],
|
|
1439
1099
|
}
|
|
@@ -1461,7 +1121,7 @@ def ask(query: str):
|
|
|
1461
1121
|
|
|
1462
1122
|
execute_file = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
1463
1123
|
|
|
1464
|
-
with open(os.path.join(execute_file), "w",encoding="utf-8") as f:
|
|
1124
|
+
with open(os.path.join(execute_file), "w", encoding="utf-8") as f:
|
|
1465
1125
|
f.write(yaml_content)
|
|
1466
1126
|
|
|
1467
1127
|
def execute_ask():
|
|
@@ -1476,50 +1136,27 @@ def ask(query: str):
|
|
|
1476
1136
|
def get_llm_friendly_package_docs(
|
|
1477
1137
|
package_name: Optional[str] = None, return_paths: bool = False
|
|
1478
1138
|
) -> 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
|
|
1139
|
+
"""
|
|
1140
|
+
Get LLM friendly package documentation using the new AC module system
|
|
1141
|
+
|
|
1142
|
+
Args:
|
|
1143
|
+
package_name: Specific package name to get docs for, None for all packages
|
|
1144
|
+
return_paths: If True, return file paths; if False, return file contents
|
|
1145
|
+
|
|
1146
|
+
Returns:
|
|
1147
|
+
List of documentation content or file paths
|
|
1148
|
+
"""
|
|
1149
|
+
from autocoder.common.llm_friendly_package import get_package_manager
|
|
1150
|
+
|
|
1151
|
+
package_manager = get_package_manager()
|
|
1152
|
+
return package_manager.get_docs(package_name, return_paths)
|
|
1516
1153
|
|
|
1517
1154
|
|
|
1518
1155
|
def convert_yaml_to_config(yaml_file: str):
|
|
1519
1156
|
from autocoder.auto_coder import AutoCoderArgs, load_include_files, Template
|
|
1520
1157
|
|
|
1521
1158
|
args = AutoCoderArgs()
|
|
1522
|
-
with open(yaml_file, "r",encoding="utf-8") as f:
|
|
1159
|
+
with open(yaml_file, "r", encoding="utf-8") as f:
|
|
1523
1160
|
config = yaml.safe_load(f)
|
|
1524
1161
|
config = load_include_files(config, yaml_file)
|
|
1525
1162
|
for key, value in config.items():
|
|
@@ -1531,150 +1168,22 @@ def convert_yaml_to_config(yaml_file: str):
|
|
|
1531
1168
|
setattr(args, key, value)
|
|
1532
1169
|
return args
|
|
1533
1170
|
|
|
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
1171
|
|
|
1659
|
-
|
|
1660
|
-
|
|
1172
|
+
def mcp(query: str):
|
|
1173
|
+
"""
|
|
1174
|
+
处理MCP命令,使用 McpHandler 进行统一处理
|
|
1661
1175
|
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1176
|
+
Args:
|
|
1177
|
+
query: 查询字符串
|
|
1178
|
+
"""
|
|
1179
|
+
from autocoder.common.file_handler import McpHandler
|
|
1665
1180
|
|
|
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
|
-
)
|
|
1181
|
+
handler = McpHandler()
|
|
1182
|
+
handler.handle_mcp_command(query)
|
|
1674
1183
|
|
|
1675
1184
|
|
|
1676
|
-
@run_in_raw_thread()
|
|
1677
1185
|
def code_next(query: str):
|
|
1186
|
+
memory = get_current_memory()
|
|
1678
1187
|
conf = memory.get("conf", {})
|
|
1679
1188
|
yaml_config = {
|
|
1680
1189
|
"include_file": ["./base/base.yml"],
|
|
@@ -1683,7 +1192,7 @@ def code_next(query: str):
|
|
|
1683
1192
|
"skip_build_index": conf.get("skip_build_index", "true") == "true",
|
|
1684
1193
|
"skip_confirm": conf.get("skip_confirm", "true") == "true",
|
|
1685
1194
|
"silence": conf.get("silence", "true") == "true",
|
|
1686
|
-
"include_project_structure": conf.get("include_project_structure", "
|
|
1195
|
+
"include_project_structure": conf.get("include_project_structure", "false")
|
|
1687
1196
|
== "true",
|
|
1688
1197
|
"exclude_files": memory.get("exclude_files", []),
|
|
1689
1198
|
}
|
|
@@ -1694,7 +1203,7 @@ def code_next(query: str):
|
|
|
1694
1203
|
|
|
1695
1204
|
temp_yaml = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
1696
1205
|
try:
|
|
1697
|
-
with open(temp_yaml, "w",encoding="utf-8") as f:
|
|
1206
|
+
with open(temp_yaml, "w", encoding="utf-8") as f:
|
|
1698
1207
|
f.write(convert_yaml_config_to_str(yaml_config=yaml_config))
|
|
1699
1208
|
args = convert_yaml_to_config(temp_yaml)
|
|
1700
1209
|
finally:
|
|
@@ -1704,8 +1213,7 @@ def code_next(query: str):
|
|
|
1704
1213
|
product_mode = conf.get("product_mode", "lite")
|
|
1705
1214
|
llm = get_single_llm(args.chat_model or args.model, product_mode=product_mode)
|
|
1706
1215
|
|
|
1707
|
-
auto_guesser = AutoGuessQuery(
|
|
1708
|
-
llm=llm, project_dir=os.getcwd(), skip_diff=True)
|
|
1216
|
+
auto_guesser = AutoGuessQuery(llm=llm, project_dir=os.getcwd(), skip_diff=True)
|
|
1709
1217
|
|
|
1710
1218
|
predicted_tasks = auto_guesser.predict_next_tasks(
|
|
1711
1219
|
5, is_human_as_model=args.human_as_model
|
|
@@ -1719,25 +1227,20 @@ def code_next(query: str):
|
|
|
1719
1227
|
console = Console()
|
|
1720
1228
|
|
|
1721
1229
|
# Create main panel for all predicted tasks
|
|
1722
|
-
table = Table(show_header=True,
|
|
1723
|
-
header_style="bold magenta", show_lines=True)
|
|
1230
|
+
table = Table(show_header=True, header_style="bold magenta", show_lines=True)
|
|
1724
1231
|
table.add_column("Priority", style="cyan", width=8)
|
|
1725
|
-
table.add_column("Task Description", style="green",
|
|
1726
|
-
width=40, overflow="fold")
|
|
1232
|
+
table.add_column("Task Description", style="green", width=40, overflow="fold")
|
|
1727
1233
|
table.add_column("Files", style="yellow", width=30, overflow="fold")
|
|
1728
1234
|
table.add_column("Reason", style="blue", width=30, overflow="fold")
|
|
1729
|
-
table.add_column("Dependencies", style="magenta",
|
|
1730
|
-
width=30, overflow="fold")
|
|
1235
|
+
table.add_column("Dependencies", style="magenta", width=30, overflow="fold")
|
|
1731
1236
|
|
|
1732
1237
|
for task in predicted_tasks:
|
|
1733
1238
|
# Format file paths to be more readable
|
|
1734
|
-
file_list = "\n".join([os.path.relpath(f, os.getcwd())
|
|
1735
|
-
for f in task.urls])
|
|
1239
|
+
file_list = "\n".join([os.path.relpath(f, os.getcwd()) for f in task.urls])
|
|
1736
1240
|
|
|
1737
1241
|
# Format dependencies to be more readable
|
|
1738
1242
|
dependencies = (
|
|
1739
|
-
"\n".join(
|
|
1740
|
-
task.dependency_queries) if task.dependency_queries else "None"
|
|
1243
|
+
"\n".join(task.dependency_queries) if task.dependency_queries else "None"
|
|
1741
1244
|
)
|
|
1742
1245
|
|
|
1743
1246
|
table.add_row(
|
|
@@ -1754,260 +1257,42 @@ def code_next(query: str):
|
|
|
1754
1257
|
)
|
|
1755
1258
|
|
|
1756
1259
|
|
|
1757
|
-
@run_in_raw_thread()
|
|
1758
1260
|
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
|
|
1261
|
+
"""
|
|
1262
|
+
处理提交命令,使用 CommitHandler 进行统一处理
|
|
1921
1263
|
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1264
|
+
Args:
|
|
1265
|
+
query: 可选的提交消息或命令
|
|
1266
|
+
"""
|
|
1267
|
+
from autocoder.common.file_handler import CommitHandler
|
|
1925
1268
|
|
|
1926
|
-
|
|
1927
|
-
|
|
1269
|
+
handler = CommitHandler()
|
|
1270
|
+
handler.handle_commit_command(query)
|
|
1928
1271
|
|
|
1929
|
-
# handle image
|
|
1930
|
-
v = Image.convert_image_paths_from(query)
|
|
1931
|
-
yaml_config["query"] = v
|
|
1932
1272
|
|
|
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
|
-
)
|
|
1273
|
+
def coding(query: str, cancel_token=None):
|
|
1274
|
+
"""
|
|
1275
|
+
处理代码生成命令,使用 CodingHandler 进行统一处理
|
|
1962
1276
|
|
|
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)
|
|
1277
|
+
Args:
|
|
1278
|
+
query: 代码生成查询字符串
|
|
1279
|
+
cancel_token: 可选的取消令牌
|
|
1280
|
+
"""
|
|
1281
|
+
from autocoder.common.file_handler import CodingHandler
|
|
1985
1282
|
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
f.write(yaml_content)
|
|
1283
|
+
handler = CodingHandler()
|
|
1284
|
+
handler.handle_coding_command(query, cancel_token)
|
|
1989
1285
|
|
|
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
1286
|
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
print("Failed to create new YAML file.")
|
|
1287
|
+
def rules(query: str):
|
|
1288
|
+
from autocoder.chat.rules_command import handle_rules_command
|
|
2001
1289
|
|
|
2002
|
-
|
|
1290
|
+
result = handle_rules_command(query, coding_func=coding)
|
|
1291
|
+
# 只有当结果不为空时才打印,避免重复输出
|
|
1292
|
+
if result and result.strip():
|
|
1293
|
+
print(result)
|
|
2003
1294
|
completer.refresh_files()
|
|
2004
1295
|
|
|
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
1296
|
|
|
2012
1297
|
@byzerllm.prompt()
|
|
2013
1298
|
def code_review(query: str) -> str:
|
|
@@ -2025,95 +1310,32 @@ def code_review(query: str) -> str:
|
|
|
2025
1310
|
如果用户的需求包含了@一个文件名 或者 @@符号, 那么重点关注这些文件或者符号(函数,类)进行上述的review。
|
|
2026
1311
|
review 过程中严格遵循上述的检查点,不要遗漏,没有发现异常的点直接跳过,只对发现的异常点,给出具体的修改后的代码。
|
|
2027
1312
|
"""
|
|
1313
|
+
return {} # type: ignore
|
|
2028
1314
|
|
|
2029
1315
|
|
|
2030
|
-
@run_in_raw_thread()
|
|
2031
1316
|
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)
|
|
1317
|
+
"""
|
|
1318
|
+
处理聊天命令,使用 ChatHandler 进行统一处理
|
|
2094
1319
|
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
auto_coder_main(cmd)
|
|
1320
|
+
Args:
|
|
1321
|
+
query: 聊天查询字符串
|
|
1322
|
+
"""
|
|
1323
|
+
from autocoder.common.file_handler import ChatHandler
|
|
2100
1324
|
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
finally:
|
|
2104
|
-
os.remove(execute_file)
|
|
1325
|
+
handler = ChatHandler()
|
|
1326
|
+
handler.handle_chat_command(query)
|
|
2105
1327
|
|
|
2106
1328
|
|
|
2107
|
-
@run_in_raw_thread()
|
|
2108
1329
|
def summon(query: str):
|
|
1330
|
+
memory = get_current_memory()
|
|
2109
1331
|
conf = memory.get("conf", {})
|
|
2110
|
-
current_files =
|
|
1332
|
+
current_files = get_current_files()
|
|
2111
1333
|
|
|
2112
1334
|
file_contents = []
|
|
2113
1335
|
for file in current_files:
|
|
2114
1336
|
if os.path.exists(file):
|
|
2115
1337
|
try:
|
|
2116
|
-
with open(file, "r",encoding="utf-8") as f:
|
|
1338
|
+
with open(file, "r", encoding="utf-8") as f:
|
|
2117
1339
|
content = f.read()
|
|
2118
1340
|
s = f"##File: {file}\n{content}\n\n"
|
|
2119
1341
|
file_contents.append(s)
|
|
@@ -2149,7 +1371,7 @@ def summon(query: str):
|
|
|
2149
1371
|
|
|
2150
1372
|
execute_file = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
2151
1373
|
|
|
2152
|
-
with open(os.path.join(execute_file), "w",encoding="utf-8") as f:
|
|
1374
|
+
with open(os.path.join(execute_file), "w", encoding="utf-8") as f:
|
|
2153
1375
|
f.write(yaml_content)
|
|
2154
1376
|
|
|
2155
1377
|
def execute_summon():
|
|
@@ -2161,9 +1383,8 @@ def summon(query: str):
|
|
|
2161
1383
|
os.remove(execute_file)
|
|
2162
1384
|
|
|
2163
1385
|
|
|
2164
|
-
@run_in_raw_thread()
|
|
2165
1386
|
def design(query: str):
|
|
2166
|
-
|
|
1387
|
+
memory = get_current_memory()
|
|
2167
1388
|
conf = memory.get("conf", {})
|
|
2168
1389
|
yaml_config = {
|
|
2169
1390
|
"include_file": ["./base/base.yml"],
|
|
@@ -2196,7 +1417,7 @@ def design(query: str):
|
|
|
2196
1417
|
|
|
2197
1418
|
execute_file = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
2198
1419
|
|
|
2199
|
-
with open(os.path.join(execute_file), "w",encoding="utf-8") as f:
|
|
1420
|
+
with open(os.path.join(execute_file), "w", encoding="utf-8") as f:
|
|
2200
1421
|
f.write(yaml_content)
|
|
2201
1422
|
|
|
2202
1423
|
def execute_design():
|
|
@@ -2208,117 +1429,21 @@ def design(query: str):
|
|
|
2208
1429
|
os.remove(execute_file)
|
|
2209
1430
|
|
|
2210
1431
|
|
|
2211
|
-
@run_in_raw_thread()
|
|
2212
1432
|
def active_context(query: str):
|
|
2213
1433
|
"""
|
|
2214
|
-
|
|
2215
|
-
|
|
1434
|
+
处理活动上下文命令,使用 ActiveContextHandler 进行统一处理
|
|
1435
|
+
|
|
2216
1436
|
Args:
|
|
2217
1437
|
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)
|
|
1438
|
+
"""
|
|
1439
|
+
from autocoder.common.file_handler import ActiveContextHandler
|
|
1440
|
+
|
|
1441
|
+
handler = ActiveContextHandler()
|
|
1442
|
+
handler.handle_active_context_command(query)
|
|
2319
1443
|
|
|
2320
1444
|
|
|
2321
1445
|
def voice_input():
|
|
1446
|
+
memory = get_current_memory()
|
|
2322
1447
|
conf = memory.get("conf", {})
|
|
2323
1448
|
yaml_config = {
|
|
2324
1449
|
"include_file": ["./base/base.yml"],
|
|
@@ -2335,7 +1460,7 @@ def voice_input():
|
|
|
2335
1460
|
|
|
2336
1461
|
execute_file = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
2337
1462
|
|
|
2338
|
-
with open(os.path.join(execute_file), "w",encoding="utf-8") as f:
|
|
1463
|
+
with open(os.path.join(execute_file), "w", encoding="utf-8") as f:
|
|
2339
1464
|
f.write(yaml_content)
|
|
2340
1465
|
|
|
2341
1466
|
def execute_voice2text_command():
|
|
@@ -2343,14 +1468,16 @@ def voice_input():
|
|
|
2343
1468
|
|
|
2344
1469
|
try:
|
|
2345
1470
|
execute_voice2text_command()
|
|
2346
|
-
with open(
|
|
1471
|
+
with open(
|
|
1472
|
+
os.path.join(".auto-coder", "exchange.txt"), "r", encoding="utf-8"
|
|
1473
|
+
) as f:
|
|
2347
1474
|
return f.read()
|
|
2348
1475
|
finally:
|
|
2349
1476
|
os.remove(execute_file)
|
|
2350
1477
|
|
|
2351
1478
|
|
|
2352
|
-
@run_in_raw_thread()
|
|
2353
1479
|
def generate_shell_command(input_text):
|
|
1480
|
+
memory = get_current_memory()
|
|
2354
1481
|
conf = memory.get("conf", {})
|
|
2355
1482
|
yaml_config = {
|
|
2356
1483
|
"include_file": ["./base/base.yml"],
|
|
@@ -2365,428 +1492,58 @@ def generate_shell_command(input_text):
|
|
|
2365
1492
|
|
|
2366
1493
|
execute_file = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
2367
1494
|
|
|
2368
|
-
with open(os.path.join(execute_file), "w",encoding="utf-8") as f:
|
|
1495
|
+
with open(os.path.join(execute_file), "w", encoding="utf-8") as f:
|
|
2369
1496
|
f.write(yaml_content)
|
|
2370
1497
|
|
|
2371
1498
|
try:
|
|
2372
1499
|
auto_coder_main(["agent", "generate_command", "--file", execute_file])
|
|
2373
|
-
with open(
|
|
1500
|
+
with open(
|
|
1501
|
+
os.path.join(".auto-coder", "exchange.txt"), "r", encoding="utf-8"
|
|
1502
|
+
) as f:
|
|
2374
1503
|
shell_script = f.read()
|
|
2375
1504
|
result_manager = ResultManager()
|
|
2376
|
-
result_manager.add_result(
|
|
2377
|
-
|
|
2378
|
-
"input": {
|
|
2379
|
-
|
|
2380
|
-
}
|
|
2381
|
-
})
|
|
1505
|
+
result_manager.add_result(
|
|
1506
|
+
content=shell_script,
|
|
1507
|
+
meta={"action": "generate_shell_command", "input": {"query": input_text}},
|
|
1508
|
+
)
|
|
2382
1509
|
return shell_script
|
|
2383
1510
|
finally:
|
|
2384
1511
|
os.remove(execute_file)
|
|
2385
1512
|
|
|
1513
|
+
|
|
2386
1514
|
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
1515
|
"""
|
|
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
|
|
1516
|
+
处理模型管理命令,使用 ModelsHandler 进行统一处理
|
|
2696
1517
|
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
"action": "models",
|
|
2702
|
-
"input": {
|
|
2703
|
-
"query": query
|
|
2704
|
-
}
|
|
2705
|
-
})
|
|
2706
|
-
return
|
|
1518
|
+
Args:
|
|
1519
|
+
query: 查询字符串,支持多种模型管理子命令
|
|
1520
|
+
"""
|
|
1521
|
+
from autocoder.common.file_handler import ModelsHandler
|
|
2707
1522
|
|
|
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
|
-
}
|
|
1523
|
+
handler = ModelsHandler()
|
|
1524
|
+
handler.handle_models_command(query)
|
|
2718
1525
|
|
|
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
1526
|
|
|
2768
1527
|
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])
|
|
1528
|
+
memory_manager = get_memory_manager()
|
|
1529
|
+
new_dirs = memory_manager.add_exclude_dirs(dir_names)
|
|
1530
|
+
|
|
1531
|
+
if new_dirs:
|
|
1532
|
+
print(f"Added exclude dirs: {new_dirs}")
|
|
1533
|
+
exclude_files(",".join([f"regex://.*/{d}/*." for d in new_dirs]))
|
|
2779
1534
|
else:
|
|
2780
1535
|
print("All specified dirs are already in the exclude list.")
|
|
2781
|
-
save_memory()
|
|
2782
1536
|
completer.refresh_files()
|
|
2783
1537
|
|
|
1538
|
+
|
|
2784
1539
|
def exclude_files(query: str):
|
|
1540
|
+
memory_manager = get_memory_manager()
|
|
2785
1541
|
result_manager = ResultManager()
|
|
2786
1542
|
printer = Printer()
|
|
1543
|
+
|
|
2787
1544
|
if "/list" in query:
|
|
2788
1545
|
query = query.replace("/list", "", 1).strip()
|
|
2789
|
-
existing_file_patterns =
|
|
1546
|
+
existing_file_patterns = memory_manager.get_exclude_files()
|
|
2790
1547
|
console = Console()
|
|
2791
1548
|
# 打印表格
|
|
2792
1549
|
table = Table(title="Exclude Files")
|
|
@@ -2794,70 +1551,58 @@ def exclude_files(query: str):
|
|
|
2794
1551
|
for file_pattern in existing_file_patterns:
|
|
2795
1552
|
table.add_row(file_pattern)
|
|
2796
1553
|
console.print(table)
|
|
2797
|
-
result_manager.add_result(
|
|
2798
|
-
"
|
|
2799
|
-
"input": {
|
|
2800
|
-
|
|
2801
|
-
}
|
|
2802
|
-
})
|
|
1554
|
+
result_manager.add_result(
|
|
1555
|
+
content=f"Exclude files: {existing_file_patterns}",
|
|
1556
|
+
meta={"action": "exclude_files", "input": {"query": query}},
|
|
1557
|
+
)
|
|
2803
1558
|
return
|
|
2804
1559
|
|
|
2805
1560
|
if "/drop" in query:
|
|
2806
1561
|
query = query.replace("/drop", "", 1).strip()
|
|
2807
|
-
|
|
2808
|
-
existing_file_patterns.remove(query.strip())
|
|
2809
|
-
memory["exclude_files"] = existing_file_patterns
|
|
2810
|
-
save_memory()
|
|
1562
|
+
removed_patterns = memory_manager.remove_exclude_files([query.strip()])
|
|
2811
1563
|
completer.refresh_files()
|
|
2812
|
-
result_manager.add_result(
|
|
2813
|
-
"
|
|
2814
|
-
"input": {
|
|
2815
|
-
|
|
2816
|
-
}
|
|
2817
|
-
})
|
|
1564
|
+
result_manager.add_result(
|
|
1565
|
+
content=f"Dropped exclude files: {removed_patterns}",
|
|
1566
|
+
meta={"action": "exclude_files", "input": {"query": query}},
|
|
1567
|
+
)
|
|
2818
1568
|
return
|
|
2819
|
-
|
|
1569
|
+
|
|
2820
1570
|
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}")
|
|
1571
|
+
|
|
1572
|
+
# Validate patterns
|
|
1573
|
+
for file_pattern in new_file_patterns:
|
|
1574
|
+
if not file_pattern.startswith("regex://"):
|
|
1575
|
+
result_manager.add_result(
|
|
1576
|
+
content=printer.get_message_from_key_with_format(
|
|
1577
|
+
"invalid_file_pattern", file_pattern=file_pattern
|
|
1578
|
+
),
|
|
1579
|
+
meta={"action": "exclude_files", "input": {"query": file_pattern}},
|
|
1580
|
+
)
|
|
1581
|
+
raise ValueError(
|
|
1582
|
+
printer.get_message_from_key_with_format(
|
|
1583
|
+
"invalid_file_pattern", file_pattern=file_pattern
|
|
1584
|
+
)
|
|
1585
|
+
)
|
|
1586
|
+
|
|
1587
|
+
# Add new patterns
|
|
1588
|
+
new_patterns_added = memory_manager.add_exclude_files(new_file_patterns)
|
|
1589
|
+
|
|
1590
|
+
if new_patterns_added:
|
|
1591
|
+
result_manager.add_result(
|
|
1592
|
+
content=f"Added exclude files: {new_patterns_added}",
|
|
1593
|
+
meta={"action": "exclude_files", "input": {"query": new_patterns_added}},
|
|
1594
|
+
)
|
|
1595
|
+
print(f"Added exclude files: {new_patterns_added}")
|
|
2848
1596
|
else:
|
|
2849
|
-
result_manager.add_result(
|
|
2850
|
-
"
|
|
2851
|
-
"input": {
|
|
2852
|
-
|
|
2853
|
-
}
|
|
2854
|
-
})
|
|
1597
|
+
result_manager.add_result(
|
|
1598
|
+
content=f"All specified files are already in the exclude list.",
|
|
1599
|
+
meta={"action": "exclude_files", "input": {"query": new_file_patterns}},
|
|
1600
|
+
)
|
|
2855
1601
|
print("All specified files are already in the exclude list.")
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
1602
|
|
|
2859
|
-
|
|
1603
|
+
|
|
2860
1604
|
def index_build():
|
|
1605
|
+
memory = get_memory()
|
|
2861
1606
|
conf = memory.get("conf", {})
|
|
2862
1607
|
yaml_config = {
|
|
2863
1608
|
"include_file": ["./base/base.yml"],
|
|
@@ -2872,17 +1617,18 @@ def index_build():
|
|
|
2872
1617
|
yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
|
|
2873
1618
|
yaml_file = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
2874
1619
|
|
|
2875
|
-
with open(yaml_file, "w",encoding="utf-8") as f:
|
|
1620
|
+
with open(yaml_file, "w", encoding="utf-8") as f:
|
|
2876
1621
|
f.write(yaml_content)
|
|
2877
|
-
try:
|
|
2878
|
-
auto_coder_main(["index", "--file", yaml_file])
|
|
1622
|
+
try:
|
|
1623
|
+
auto_coder_main(["index", "--file", yaml_file])
|
|
2879
1624
|
completer.refresh_files()
|
|
2880
1625
|
finally:
|
|
2881
1626
|
os.remove(yaml_file)
|
|
2882
1627
|
|
|
2883
1628
|
|
|
2884
|
-
def get_final_config()->AutoCoderArgs:
|
|
2885
|
-
|
|
1629
|
+
def get_final_config() -> AutoCoderArgs:
|
|
1630
|
+
memory_manager = get_memory_manager()
|
|
1631
|
+
conf = memory_manager.get_all_config()
|
|
2886
1632
|
yaml_config = {
|
|
2887
1633
|
"include_file": ["./base/base.yml"],
|
|
2888
1634
|
"auto_merge": conf.get("auto_merge", "editblock"),
|
|
@@ -2890,9 +1636,9 @@ def get_final_config()->AutoCoderArgs:
|
|
|
2890
1636
|
"skip_build_index": conf.get("skip_build_index", "true") == "true",
|
|
2891
1637
|
"skip_confirm": conf.get("skip_confirm", "true") == "true",
|
|
2892
1638
|
"silence": conf.get("silence", "true") == "true",
|
|
2893
|
-
"include_project_structure": conf.get("include_project_structure", "
|
|
1639
|
+
"include_project_structure": conf.get("include_project_structure", "false")
|
|
2894
1640
|
== "true",
|
|
2895
|
-
"exclude_files":
|
|
1641
|
+
"exclude_files": memory_manager.get_exclude_files(),
|
|
2896
1642
|
}
|
|
2897
1643
|
for key, value in conf.items():
|
|
2898
1644
|
converted_value = convert_config_value(key, value)
|
|
@@ -2901,7 +1647,7 @@ def get_final_config()->AutoCoderArgs:
|
|
|
2901
1647
|
|
|
2902
1648
|
temp_yaml = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
2903
1649
|
try:
|
|
2904
|
-
with open(temp_yaml, "w",encoding="utf-8") as f:
|
|
1650
|
+
with open(temp_yaml, "w", encoding="utf-8") as f:
|
|
2905
1651
|
f.write(convert_yaml_config_to_str(yaml_config=yaml_config))
|
|
2906
1652
|
args = convert_yaml_to_config(temp_yaml)
|
|
2907
1653
|
finally:
|
|
@@ -2909,18 +1655,31 @@ def get_final_config()->AutoCoderArgs:
|
|
|
2909
1655
|
os.remove(temp_yaml)
|
|
2910
1656
|
return args
|
|
2911
1657
|
|
|
1658
|
+
|
|
2912
1659
|
def help(query: str):
|
|
2913
|
-
from autocoder.common.auto_configure import
|
|
1660
|
+
from autocoder.common.auto_configure import (
|
|
1661
|
+
ConfigAutoTuner,
|
|
1662
|
+
MemoryConfig,
|
|
1663
|
+
AutoConfigRequest,
|
|
1664
|
+
)
|
|
1665
|
+
|
|
1666
|
+
memory_manager = get_memory_manager()
|
|
1667
|
+
memory = get_memory()
|
|
2914
1668
|
args = get_final_config()
|
|
2915
|
-
product_mode =
|
|
1669
|
+
product_mode = memory_manager.get_config("product_mode", "lite")
|
|
2916
1670
|
llm = get_single_llm(args.chat_model or args.model, product_mode=product_mode)
|
|
2917
|
-
auto_config_tuner = ConfigAutoTuner(
|
|
2918
|
-
|
|
1671
|
+
auto_config_tuner = ConfigAutoTuner(
|
|
1672
|
+
args=args,
|
|
1673
|
+
llm=llm,
|
|
1674
|
+
memory_config=MemoryConfig(memory=memory, save_memory_func=save_memory),
|
|
1675
|
+
)
|
|
1676
|
+
auto_config_tuner.tune(AutoConfigRequest(query=query))
|
|
1677
|
+
|
|
2919
1678
|
|
|
2920
|
-
@run_in_raw_thread()
|
|
2921
1679
|
def index_export(path: str):
|
|
2922
1680
|
from autocoder.common.index_import_export import export_index
|
|
2923
1681
|
from autocoder.common.printer import Printer
|
|
1682
|
+
|
|
2924
1683
|
printer = Printer()
|
|
2925
1684
|
project_root = os.getcwd()
|
|
2926
1685
|
if export_index(project_root, path):
|
|
@@ -2928,10 +1687,11 @@ def index_export(path: str):
|
|
|
2928
1687
|
else:
|
|
2929
1688
|
printer.print_in_terminal("index_export_fail", path=path)
|
|
2930
1689
|
|
|
2931
|
-
|
|
1690
|
+
|
|
2932
1691
|
def index_import(path: str):
|
|
2933
1692
|
from autocoder.common.index_import_export import import_index
|
|
2934
1693
|
from autocoder.common.printer import Printer
|
|
1694
|
+
|
|
2935
1695
|
printer = Printer()
|
|
2936
1696
|
project_root = os.getcwd()
|
|
2937
1697
|
if import_index(project_root, path):
|
|
@@ -2939,7 +1699,7 @@ def index_import(path: str):
|
|
|
2939
1699
|
else:
|
|
2940
1700
|
printer.print_in_terminal("index_import_fail", path=path)
|
|
2941
1701
|
|
|
2942
|
-
|
|
1702
|
+
|
|
2943
1703
|
def index_query(query: str):
|
|
2944
1704
|
from autocoder.index.entry import build_index_and_filter_files
|
|
2945
1705
|
from autocoder.pyproject import PyProject
|
|
@@ -2949,7 +1709,9 @@ def index_query(query: str):
|
|
|
2949
1709
|
config = get_final_config()
|
|
2950
1710
|
config.query = query
|
|
2951
1711
|
config.skip_filter_index = False
|
|
2952
|
-
llm = get_single_llm(
|
|
1712
|
+
llm = get_single_llm(
|
|
1713
|
+
config.chat_model or config.model, product_mode=config.product_mode
|
|
1714
|
+
)
|
|
2953
1715
|
|
|
2954
1716
|
if config.project_type == "ts":
|
|
2955
1717
|
pp = TSProject(args=config, llm=llm)
|
|
@@ -2958,264 +1720,79 @@ def index_query(query: str):
|
|
|
2958
1720
|
else:
|
|
2959
1721
|
pp = SuffixProject(args=config, llm=llm, file_filter=None)
|
|
2960
1722
|
pp.run()
|
|
2961
|
-
sources = pp.sources
|
|
2962
|
-
source_code_list = build_index_and_filter_files(
|
|
2963
|
-
|
|
1723
|
+
sources = pp.sources
|
|
1724
|
+
source_code_list = build_index_and_filter_files(
|
|
1725
|
+
llm=llm, args=config, sources=sources
|
|
1726
|
+
)
|
|
1727
|
+
return source_code_list
|
|
1728
|
+
|
|
2964
1729
|
|
|
2965
1730
|
def list_files():
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
1731
|
+
"""
|
|
1732
|
+
处理文件列表命令,使用 ListFilesHandler 进行统一处理
|
|
1733
|
+
"""
|
|
1734
|
+
from autocoder.common.file_handler import ListFilesHandler
|
|
2969
1735
|
|
|
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
|
-
)
|
|
1736
|
+
handler = ListFilesHandler()
|
|
1737
|
+
handler.handle_list_files_command()
|
|
2986
1738
|
|
|
2987
1739
|
|
|
2988
1740
|
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
1741
|
printer = Printer()
|
|
2994
1742
|
console = Console()
|
|
2995
1743
|
# Generate the shell script
|
|
2996
|
-
shell_script = generate_shell_command(query)
|
|
1744
|
+
shell_script = generate_shell_command(query)
|
|
2997
1745
|
|
|
2998
1746
|
# Ask for confirmation using rich
|
|
2999
1747
|
if Confirm.ask(
|
|
3000
|
-
printer.get_message_from_key("confirm_execute_shell_script"),
|
|
3001
|
-
default=False
|
|
1748
|
+
printer.get_message_from_key("confirm_execute_shell_script"), default=False
|
|
3002
1749
|
):
|
|
3003
1750
|
execute_shell_command(shell_script)
|
|
3004
1751
|
else:
|
|
3005
1752
|
console.print(
|
|
3006
1753
|
Panel(
|
|
3007
1754
|
printer.get_message_from_key("shell_script_not_executed"),
|
|
3008
|
-
border_style="yellow"
|
|
1755
|
+
border_style="yellow",
|
|
3009
1756
|
)
|
|
3010
1757
|
)
|
|
3011
1758
|
|
|
3012
1759
|
|
|
3013
1760
|
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
|
-
)
|
|
1761
|
+
"""
|
|
1762
|
+
处理库管理命令,使用 LibHandler 进行统一处理
|
|
3180
1763
|
|
|
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}")
|
|
1764
|
+
Args:
|
|
1765
|
+
args: 命令参数列表
|
|
1766
|
+
"""
|
|
1767
|
+
from autocoder.common.file_handler import LibHandler
|
|
3196
1768
|
|
|
3197
|
-
|
|
3198
|
-
|
|
1769
|
+
handler = LibHandler()
|
|
1770
|
+
handler.handle_lib_command(args)
|
|
3199
1771
|
|
|
3200
1772
|
|
|
3201
1773
|
def execute_shell_command(command: str):
|
|
3202
1774
|
from autocoder.common.shells import execute_shell_command as shell_exec
|
|
1775
|
+
|
|
3203
1776
|
shell_exec(command)
|
|
3204
1777
|
|
|
3205
1778
|
|
|
3206
1779
|
def conf_export(path: str):
|
|
3207
1780
|
from autocoder.common.conf_import_export import export_conf
|
|
1781
|
+
|
|
3208
1782
|
export_conf(os.getcwd(), path)
|
|
3209
1783
|
|
|
1784
|
+
|
|
3210
1785
|
def conf_import(path: str):
|
|
3211
1786
|
from autocoder.common.conf_import_export import import_conf
|
|
1787
|
+
|
|
3212
1788
|
import_conf(os.getcwd(), path)
|
|
3213
1789
|
|
|
1790
|
+
|
|
3214
1791
|
def generate_new_yaml(query: str):
|
|
3215
1792
|
memory = get_memory()
|
|
3216
|
-
conf = memory.get("conf",{})
|
|
3217
|
-
current_files = memory.get("current_files",{}).get("files",[])
|
|
3218
|
-
auto_coder_main(["next", "chat_action"])
|
|
1793
|
+
conf = memory.get("conf", {})
|
|
1794
|
+
current_files = memory.get("current_files", {}).get("files", [])
|
|
1795
|
+
auto_coder_main(["next", "chat_action"])
|
|
3219
1796
|
latest_yaml_file = get_last_yaml_file("actions")
|
|
3220
1797
|
if latest_yaml_file:
|
|
3221
1798
|
yaml_config = {
|
|
@@ -3225,11 +1802,11 @@ def generate_new_yaml(query: str):
|
|
|
3225
1802
|
"skip_build_index": conf.get("skip_build_index", "true") == "true",
|
|
3226
1803
|
"skip_confirm": conf.get("skip_confirm", "true") == "true",
|
|
3227
1804
|
"silence": conf.get("silence", "true") == "true",
|
|
3228
|
-
"include_project_structure": conf.get("include_project_structure", "
|
|
1805
|
+
"include_project_structure": conf.get("include_project_structure", "false")
|
|
3229
1806
|
== "true",
|
|
3230
1807
|
"exclude_files": memory.get("exclude_files", []),
|
|
3231
1808
|
}
|
|
3232
|
-
yaml_config["context"] = ""
|
|
1809
|
+
yaml_config["context"] = ""
|
|
3233
1810
|
for key, value in conf.items():
|
|
3234
1811
|
converted_value = convert_config_value(key, value)
|
|
3235
1812
|
if converted_value is not None:
|
|
@@ -3240,310 +1817,356 @@ def generate_new_yaml(query: str):
|
|
|
3240
1817
|
)
|
|
3241
1818
|
# handle image
|
|
3242
1819
|
v = Image.convert_image_paths_from(query)
|
|
3243
|
-
yaml_config["query"] = v
|
|
1820
|
+
yaml_config["query"] = v
|
|
3244
1821
|
|
|
3245
|
-
yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
|
|
1822
|
+
yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
|
|
3246
1823
|
|
|
3247
1824
|
execute_file = os.path.join("actions", latest_yaml_file)
|
|
3248
|
-
with open(os.path.join(execute_file), "w",encoding="utf-8") as f:
|
|
1825
|
+
with open(os.path.join(execute_file), "w", encoding="utf-8") as f:
|
|
3249
1826
|
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",[])
|
|
1827
|
+
return execute_file, convert_yaml_to_config(execute_file)
|
|
3272
1828
|
|
|
3273
|
-
command_infos = parse_query(query)
|
|
3274
1829
|
|
|
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:])
|
|
1830
|
+
def handle_conversation_actions(conversation_config) -> bool:
|
|
1831
|
+
"""
|
|
1832
|
+
处理对话列表和创建新对话的操作
|
|
3298
1833
|
|
|
3299
|
-
|
|
3300
|
-
|
|
1834
|
+
Args:
|
|
1835
|
+
conversation_config: 对话配置对象
|
|
3301
1836
|
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
1837
|
+
Returns:
|
|
1838
|
+
bool: 如果处理了特殊操作(LIST或NEW without input)返回True,否则返回False
|
|
1839
|
+
"""
|
|
1840
|
+
if not conversation_config:
|
|
1841
|
+
return False
|
|
3306
1842
|
|
|
3307
|
-
|
|
1843
|
+
console = Console()
|
|
3308
1844
|
|
|
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
|
-
)
|
|
1845
|
+
# 处理LIST操作
|
|
1846
|
+
if conversation_config.action == ConversationAction.LIST:
|
|
1847
|
+
conversation_manager = get_conversation_manager()
|
|
1848
|
+
conversations = conversation_manager.list_conversations()
|
|
1849
|
+
# 只保留 conversation_id 和 name 字段
|
|
1850
|
+
filtered_conversations = []
|
|
1851
|
+
for conv in conversations:
|
|
1852
|
+
filtered_conv = {
|
|
1853
|
+
"conversation_id": conv.get("conversation_id"),
|
|
1854
|
+
"name": conv.get("name"),
|
|
1855
|
+
}
|
|
1856
|
+
filtered_conversations.append(filtered_conv)
|
|
3343
1857
|
|
|
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
|
-
))
|
|
1858
|
+
# 格式化 JSON 输出,使用 JSON 格式渲染而不是 Markdown
|
|
1859
|
+
json_str = json.dumps(filtered_conversations, ensure_ascii=False, indent=4)
|
|
1860
|
+
console.print(
|
|
1861
|
+
Panel(
|
|
1862
|
+
json_str,
|
|
1863
|
+
title="🏁 Task Completion",
|
|
1864
|
+
border_style="green",
|
|
1865
|
+
title_align="left",
|
|
1866
|
+
)
|
|
1867
|
+
)
|
|
1868
|
+
return True
|
|
3376
1869
|
|
|
3377
|
-
#
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
1870
|
+
# 处理NEW操作且没有用户输入
|
|
1871
|
+
if (
|
|
1872
|
+
conversation_config.action == ConversationAction.NEW
|
|
1873
|
+
and not conversation_config.query.strip()
|
|
1874
|
+
):
|
|
1875
|
+
conversation_manager = get_conversation_manager()
|
|
1876
|
+
conversation_id = conversation_manager.create_conversation(
|
|
1877
|
+
name=conversation_config.query or "New Conversation",
|
|
1878
|
+
description=conversation_config.query or "New Conversation",
|
|
1879
|
+
)
|
|
1880
|
+
conversation_manager.set_current_conversation(conversation_id)
|
|
1881
|
+
conversation_message = f"New conversation created: {conversation_manager.get_current_conversation_id()}"
|
|
3389
1882
|
|
|
1883
|
+
# 使用safe console print的简单版本
|
|
1884
|
+
try:
|
|
1885
|
+
console.print(
|
|
1886
|
+
Panel(
|
|
1887
|
+
Markdown(conversation_message),
|
|
1888
|
+
title="🏁 Task Completion",
|
|
1889
|
+
border_style="green",
|
|
1890
|
+
title_align="left",
|
|
1891
|
+
)
|
|
1892
|
+
)
|
|
1893
|
+
except Exception:
|
|
1894
|
+
# fallback to plain text
|
|
1895
|
+
safe_content = conversation_message.replace("[", "\\[").replace("]", "\\]")
|
|
1896
|
+
console.print(
|
|
1897
|
+
Panel(
|
|
1898
|
+
safe_content,
|
|
1899
|
+
title="🏁 Task Completion",
|
|
1900
|
+
border_style="green",
|
|
1901
|
+
title_align="left",
|
|
1902
|
+
)
|
|
1903
|
+
)
|
|
1904
|
+
return True
|
|
1905
|
+
|
|
1906
|
+
return False
|
|
1907
|
+
|
|
1908
|
+
|
|
1909
|
+
# used in /auto command in terminal
|
|
1910
|
+
def run_agentic(
|
|
1911
|
+
query: str,
|
|
1912
|
+
cancel_token: Optional[str] = None,
|
|
1913
|
+
conversation_history: Optional[List[Dict[str, Any]]] = None,
|
|
1914
|
+
):
|
|
1915
|
+
"""处理/auto指令"""
|
|
1916
|
+
agentic = RunAgentic()
|
|
1917
|
+
return agentic.run(query, cancel_token, conversation_history)
|
|
1918
|
+
|
|
1919
|
+
|
|
1920
|
+
def run_agentic_filter(query: str, cancel_token: Optional[str] = None):
|
|
1921
|
+
"""处理/auto指令"""
|
|
1922
|
+
agentic = RunAgentic()
|
|
1923
|
+
return agentic.filter(query, cancel_token)
|
|
1924
|
+
|
|
1925
|
+
|
|
1926
|
+
# used in autocoder/sdk/core/bridge.py
|
|
1927
|
+
def run_auto_command(
|
|
1928
|
+
query: str,
|
|
1929
|
+
pre_commit: bool = False,
|
|
1930
|
+
post_commit: bool = False,
|
|
1931
|
+
pr: bool = False,
|
|
1932
|
+
extra_args: Dict[str, Any] = {},
|
|
1933
|
+
cancel_token: Optional[str] = None,
|
|
1934
|
+
conversation_history: Optional[List[Dict[str, Any]]] = None,
|
|
1935
|
+
system_prompt: Optional[str] = None,
|
|
1936
|
+
conversation_action: ConversationAction = ConversationAction.NEW,
|
|
1937
|
+
conversation_id: Optional[str] = None,
|
|
1938
|
+
is_sub_agent: bool = False,
|
|
1939
|
+
):
|
|
1940
|
+
"""处理/auto指令"""
|
|
1941
|
+
agentic = RunAgentic()
|
|
1942
|
+
for event in agentic.run_with_events(
|
|
1943
|
+
query,
|
|
1944
|
+
pre_commit=pre_commit,
|
|
1945
|
+
post_commit=post_commit,
|
|
1946
|
+
pr=pr,
|
|
1947
|
+
extra_args=extra_args,
|
|
1948
|
+
cancel_token=cancel_token,
|
|
1949
|
+
conversation_history=conversation_history,
|
|
1950
|
+
system_prompt=system_prompt,
|
|
1951
|
+
conversation_action=conversation_action,
|
|
1952
|
+
conversation_id=conversation_id,
|
|
1953
|
+
is_sub_agent=is_sub_agent,
|
|
1954
|
+
):
|
|
1955
|
+
yield event
|
|
3390
1956
|
|
|
3391
1957
|
|
|
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",[])
|
|
1958
|
+
# used in auto-coder.web
|
|
1959
|
+
def auto_command(query: str, extra_args: Dict[str, Any] = {}):
|
|
1960
|
+
"""处理/auto指令"""
|
|
1961
|
+
args = get_final_config()
|
|
1962
|
+
memory = get_memory()
|
|
1963
|
+
if args.enable_agentic_edit:
|
|
1964
|
+
from autocoder.run_context import get_run_context, RunMode
|
|
1965
|
+
|
|
1966
|
+
execute_file, _ = generate_new_yaml(query)
|
|
1967
|
+
args.file = execute_file
|
|
1968
|
+
current_files = memory.get("current_files", {}).get("files", [])
|
|
3406
1969
|
sources = []
|
|
3407
1970
|
for file in current_files:
|
|
3408
1971
|
try:
|
|
3409
|
-
with open(file,"r",encoding="utf-8") as f:
|
|
3410
|
-
sources.append(SourceCode(module_name=file,source_code=f.read()))
|
|
1972
|
+
with open(file, "r", encoding="utf-8") as f:
|
|
1973
|
+
sources.append(SourceCode(module_name=file, source_code=f.read()))
|
|
3411
1974
|
except Exception as e:
|
|
3412
1975
|
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
1976
|
|
|
3417
|
-
|
|
1977
|
+
try:
|
|
1978
|
+
llm = get_single_llm(
|
|
1979
|
+
args.code_model or args.model, product_mode=args.product_mode
|
|
1980
|
+
)
|
|
1981
|
+
except ValueError as e:
|
|
1982
|
+
console = Console()
|
|
1983
|
+
console.print(
|
|
1984
|
+
Panel(
|
|
1985
|
+
f"[red]LLM Configuration Error:[/red]\n\n{str(e)}",
|
|
1986
|
+
title="[red]Error[/red]",
|
|
1987
|
+
border_style="red",
|
|
1988
|
+
padding=(1, 2),
|
|
1989
|
+
)
|
|
1990
|
+
)
|
|
1991
|
+
return
|
|
1992
|
+
conversation_history = extra_args.get("conversations", [])
|
|
1993
|
+
|
|
1994
|
+
command_infos = parse_query(query)
|
|
3418
1995
|
|
|
3419
1996
|
# terminal 的总是接着上次对话, 所以这里总是设置为 resume
|
|
3420
1997
|
conversation_config = AgenticEditConversationConfig(
|
|
3421
|
-
action=
|
|
1998
|
+
action=ConversationAction.RESUME
|
|
3422
1999
|
)
|
|
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"
|
|
2000
|
+
|
|
2001
|
+
task_query = query
|
|
2002
|
+
|
|
2003
|
+
if "new" in command_infos:
|
|
2004
|
+
conversation_config.action = ConversationAction.NEW
|
|
3436
2005
|
task_query = " ".join(command_infos["new"]["args"])
|
|
3437
|
-
|
|
2006
|
+
|
|
3438
2007
|
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:])
|
|
2008
|
+
conversation_config.action = ConversationAction.RESUME
|
|
2009
|
+
conversation_config.conversation_id = command_infos["resume"]["args"][0]
|
|
2010
|
+
task_query = " ".join(command_infos["resume"]["args"][1:])
|
|
3442
2011
|
|
|
3443
2012
|
if "list" in command_infos:
|
|
3444
|
-
conversation_config.action =
|
|
2013
|
+
conversation_config.action = ConversationAction.LIST
|
|
3445
2014
|
|
|
3446
|
-
|
|
3447
2015
|
if "command" in command_infos:
|
|
3448
|
-
conversation_config.action =
|
|
2016
|
+
conversation_config.action = ConversationAction.COMMAND
|
|
3449
2017
|
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
|
-
|
|
2018
|
+
|
|
2019
|
+
conversation_config.query = task_query
|
|
2020
|
+
|
|
2021
|
+
# 处理特殊的conversation操作(LIST和NEW without input)
|
|
2022
|
+
if handle_conversation_actions(conversation_config):
|
|
2023
|
+
return conversation_config.conversation_id
|
|
2024
|
+
|
|
2025
|
+
conversation_manager = get_conversation_manager()
|
|
2026
|
+
if conversation_config.action == ConversationAction.NEW:
|
|
2027
|
+
conversation_id = conversation_manager.create_conversation(
|
|
2028
|
+
name=conversation_config.query or "New Conversation",
|
|
2029
|
+
description=conversation_config.query or "New Conversation",
|
|
2030
|
+
)
|
|
2031
|
+
conversation_manager.set_current_conversation(conversation_id)
|
|
2032
|
+
conversation_config.conversation_id = conversation_id
|
|
2033
|
+
|
|
2034
|
+
if (
|
|
2035
|
+
conversation_config.action == ConversationAction.RESUME
|
|
2036
|
+
and conversation_config.conversation_id
|
|
2037
|
+
):
|
|
2038
|
+
conversation_manager.set_current_conversation(
|
|
2039
|
+
conversation_config.conversation_id
|
|
2040
|
+
)
|
|
2041
|
+
|
|
2042
|
+
if (
|
|
2043
|
+
conversation_config.action == ConversationAction.RESUME
|
|
2044
|
+
and not conversation_config.conversation_id
|
|
2045
|
+
and conversation_manager.get_current_conversation_id()
|
|
2046
|
+
):
|
|
2047
|
+
conversation_config.conversation_id = (
|
|
2048
|
+
conversation_manager.get_current_conversation_id()
|
|
2049
|
+
)
|
|
2050
|
+
conversation_manager.set_current_conversation(
|
|
2051
|
+
conversation_config.conversation_id
|
|
2052
|
+
)
|
|
2053
|
+
|
|
2054
|
+
if not conversation_config.conversation_id:
|
|
2055
|
+
conversation_id = conversation_manager.create_conversation(
|
|
2056
|
+
name=conversation_config.query or "New Conversation",
|
|
2057
|
+
description=conversation_config.query or "New Conversation",
|
|
2058
|
+
)
|
|
2059
|
+
conversation_manager.set_current_conversation(conversation_id)
|
|
2060
|
+
conversation_config.conversation_id = conversation_id
|
|
2061
|
+
|
|
2062
|
+
cancel_token = extra_args.get("event_file_id", None)
|
|
2063
|
+
global_logger.info(f"cancel_token: {cancel_token}")
|
|
2064
|
+
if cancel_token:
|
|
2065
|
+
global_cancel.register_token(cancel_token)
|
|
2066
|
+
|
|
2067
|
+
if get_run_context().mode == RunMode.WEB:
|
|
2068
|
+
runner = FileBasedEventRunner(
|
|
2069
|
+
llm=llm,
|
|
2070
|
+
args=args,
|
|
2071
|
+
conversation_config=conversation_config,
|
|
2072
|
+
cancel_token=cancel_token,
|
|
2073
|
+
)
|
|
2074
|
+
runner.run(AgenticEditRequest(user_input=task_query))
|
|
2075
|
+
|
|
2076
|
+
if get_run_context().mode == RunMode.TERMINAL:
|
|
2077
|
+
runner = TerminalRunner(
|
|
2078
|
+
llm=llm,
|
|
2079
|
+
args=args,
|
|
2080
|
+
conversation_config=conversation_config,
|
|
2081
|
+
cancel_token=cancel_token,
|
|
2082
|
+
)
|
|
2083
|
+
runner.run(AgenticEditRequest(user_input=task_query))
|
|
2084
|
+
|
|
3476
2085
|
completer.refresh_files()
|
|
3477
|
-
return
|
|
3478
|
-
|
|
3479
|
-
args = get_final_config()
|
|
2086
|
+
return conversation_config.conversation_id
|
|
2087
|
+
|
|
2088
|
+
args = get_final_config()
|
|
3480
2089
|
# 准备请求参数
|
|
3481
|
-
request = AutoCommandRequest(
|
|
3482
|
-
user_input=query
|
|
3483
|
-
)
|
|
2090
|
+
request = AutoCommandRequest(user_input=query)
|
|
3484
2091
|
|
|
3485
2092
|
# 初始化调优器
|
|
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
|
-
|
|
2093
|
+
try:
|
|
2094
|
+
llm = get_single_llm(
|
|
2095
|
+
args.chat_model or args.model, product_mode=args.product_mode
|
|
2096
|
+
)
|
|
2097
|
+
except ValueError as e:
|
|
2098
|
+
console = Console()
|
|
2099
|
+
console.print(
|
|
2100
|
+
Panel(
|
|
2101
|
+
f"[red]LLM Configuration Error:[/red]\n\n{str(e)}",
|
|
2102
|
+
title="[red]Error[/red]",
|
|
2103
|
+
border_style="red",
|
|
2104
|
+
padding=(1, 2),
|
|
2105
|
+
)
|
|
2106
|
+
)
|
|
2107
|
+
return
|
|
2108
|
+
tuner = CommandAutoTuner(
|
|
2109
|
+
llm,
|
|
2110
|
+
args=args,
|
|
2111
|
+
memory_config=MemoryConfig(memory=memory, save_memory_func=save_memory),
|
|
2112
|
+
command_config=CommandConfig(
|
|
2113
|
+
add_files=add_files,
|
|
2114
|
+
remove_files=remove_files,
|
|
2115
|
+
list_files=list_files,
|
|
2116
|
+
conf=configure,
|
|
2117
|
+
revert=revert,
|
|
2118
|
+
commit=commit,
|
|
2119
|
+
help=help,
|
|
2120
|
+
exclude_dirs=exclude_dirs,
|
|
2121
|
+
exclude_files=exclude_files,
|
|
2122
|
+
ask=ask,
|
|
2123
|
+
chat=chat,
|
|
2124
|
+
coding=coding,
|
|
2125
|
+
design=design,
|
|
2126
|
+
summon=summon,
|
|
2127
|
+
lib=lib_command,
|
|
2128
|
+
mcp=mcp,
|
|
2129
|
+
models=manage_models,
|
|
2130
|
+
index_build=index_build,
|
|
2131
|
+
index_query=index_query,
|
|
2132
|
+
execute_shell_command=execute_shell_command,
|
|
2133
|
+
generate_shell_command=generate_shell_command,
|
|
2134
|
+
conf_export=conf_export,
|
|
2135
|
+
conf_import=conf_import,
|
|
2136
|
+
index_export=index_export,
|
|
2137
|
+
index_import=index_import,
|
|
2138
|
+
),
|
|
2139
|
+
)
|
|
3517
2140
|
|
|
3518
2141
|
# 生成建议
|
|
3519
2142
|
response = tuner.analyze(request)
|
|
3520
2143
|
printer = Printer()
|
|
3521
2144
|
# 显示建议
|
|
3522
|
-
console = Console()
|
|
3523
|
-
console.print(
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
2145
|
+
console = Console()
|
|
2146
|
+
console.print(
|
|
2147
|
+
Panel(
|
|
2148
|
+
Markdown(response.reasoning or ""),
|
|
2149
|
+
title=printer.get_message_from_key_with_format(
|
|
2150
|
+
"auto_command_reasoning_title"
|
|
2151
|
+
),
|
|
2152
|
+
border_style="blue",
|
|
2153
|
+
padding=(1, 2),
|
|
2154
|
+
)
|
|
2155
|
+
)
|
|
3534
2156
|
completer.refresh_files()
|
|
2157
|
+
return None
|
|
3535
2158
|
|
|
3536
2159
|
|
|
3537
2160
|
def render_command_file_with_variables(command_infos: Dict[str, Any]) -> str:
|
|
3538
2161
|
"""
|
|
3539
2162
|
使用 CommandManager 加载并渲染命令文件
|
|
3540
|
-
|
|
2163
|
+
|
|
3541
2164
|
Args:
|
|
3542
2165
|
command_infos: parse_query(query) 的返回结果,包含命令和参数信息
|
|
3543
|
-
|
|
2166
|
+
|
|
3544
2167
|
Returns:
|
|
3545
2168
|
str: 渲染后的文件内容
|
|
3546
|
-
|
|
2169
|
+
|
|
3547
2170
|
Raises:
|
|
3548
2171
|
ValueError: 当参数不足或文件不存在时
|
|
3549
2172
|
Exception: 当渲染过程出现错误时
|
|
@@ -3552,31 +2175,33 @@ def render_command_file_with_variables(command_infos: Dict[str, Any]) -> str:
|
|
|
3552
2175
|
# 获取第一个命令的信息
|
|
3553
2176
|
if not command_infos:
|
|
3554
2177
|
raise ValueError("command_infos 为空,无法获取命令信息")
|
|
3555
|
-
|
|
2178
|
+
|
|
3556
2179
|
# command 的位置参数作为路径
|
|
3557
2180
|
first_command = command_infos["command"]
|
|
3558
|
-
|
|
2181
|
+
|
|
3559
2182
|
# 获取位置参数(文件路径)
|
|
3560
2183
|
args = first_command.get("args", [])
|
|
3561
2184
|
if not args:
|
|
3562
2185
|
raise ValueError("未提供文件路径参数")
|
|
3563
|
-
|
|
2186
|
+
|
|
3564
2187
|
file_path = args[0] # 第一个位置参数作为文件路径
|
|
3565
|
-
|
|
2188
|
+
|
|
3566
2189
|
# 获取关键字参数作为渲染参数
|
|
3567
2190
|
kwargs = first_command.get("kwargs", {})
|
|
3568
|
-
|
|
2191
|
+
|
|
3569
2192
|
# 初始化 CommandManager
|
|
3570
2193
|
command_manager = CommandManager()
|
|
3571
|
-
|
|
2194
|
+
|
|
3572
2195
|
# 使用 read_command_file_with_render 直接读取并渲染命令文件
|
|
3573
|
-
rendered_content = command_manager.read_command_file_with_render(
|
|
2196
|
+
rendered_content = command_manager.read_command_file_with_render(
|
|
2197
|
+
file_path, kwargs
|
|
2198
|
+
)
|
|
3574
2199
|
if rendered_content is None:
|
|
3575
2200
|
raise ValueError(f"无法读取或渲染命令文件: {file_path}")
|
|
3576
|
-
|
|
2201
|
+
|
|
3577
2202
|
global_logger.info(f"成功渲染命令文件: {file_path}, 使用参数: {kwargs}")
|
|
3578
2203
|
return rendered_content
|
|
3579
|
-
|
|
2204
|
+
|
|
3580
2205
|
except Exception as e:
|
|
3581
2206
|
global_logger.error(f"render_command_file_with_variables 执行失败: {str(e)}")
|
|
3582
|
-
raise
|
|
2207
|
+
raise
|