auto-coder 0.1.400__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-0.1.400.dist-info → auto_coder-2.0.0.dist-info}/WHEEL +1 -1
- {auto_coder-0.1.400.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 +25 -4
- 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 +1029 -2310
- 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 +1021 -372
- autocoder/chat_auto_coder_lang.py +23 -732
- autocoder/commands/auto_command.py +26 -9
- 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/file_monitor/test_file_monitor.py +307 -0
- autocoder/common/git_utils.py +51 -10
- 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 +746 -0
- autocoder/common/{context_pruner.py → pruner/context_pruner.py} +137 -40
- 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/{conversation_pruner.py → pruner/conversation_pruner.py} +26 -6
- autocoder/common/pruner/test_agentic_conversation_pruner.py +784 -0
- autocoder/common/pruner/test_context_pruner.py +546 -0
- 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/__init__.py +15 -0
- autocoder/common/tokens/counter.py +44 -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 +2729 -2052
- autocoder/common/v2/agent/agentic_edit_change_manager.py +474 -0
- autocoder/common/v2/agent/agentic_edit_tools/__init__.py +43 -2
- autocoder/common/v2/agent/agentic_edit_tools/ac_mod_list_tool_resolver.py +279 -0
- autocoder/common/v2/agent/agentic_edit_tools/ac_mod_read_tool_resolver.py +40 -0
- autocoder/common/v2/agent/agentic_edit_tools/ac_mod_write_tool_resolver.py +52 -0
- autocoder/common/v2/agent/agentic_edit_tools/ask_followup_question_tool_resolver.py +8 -0
- 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 +565 -30
- 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 +244 -51
- 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 +409 -140
- 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 +209 -194
- autocoder/common/v2/agent/agentic_edit_tools/todo_read_tool_resolver.py +135 -0
- autocoder/common/v2/agent/agentic_edit_tools/todo_write_tool_resolver.py +328 -0
- 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 +386 -10
- autocoder/common/v2/agent/runner/__init__.py +31 -0
- autocoder/common/v2/agent/runner/base_runner.py +92 -0
- autocoder/common/v2/agent/runner/file_based_event_runner.py +217 -0
- autocoder/common/v2/agent/runner/sdk_runner.py +182 -0
- autocoder/common/v2/agent/runner/terminal_runner.py +396 -0
- autocoder/common/v2/agent/runner/tool_display.py +589 -0
- 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 +117 -125
- autocoder/{agent → index/filter}/agentic_filter.py +323 -334
- 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 +156 -37
- 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/run_context.py +9 -0
- autocoder/sdk/__init__.py +50 -161
- 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 +158 -170
- autocoder/sdk/cli/options.py +95 -22
- autocoder/sdk/constants.py +139 -51
- autocoder/sdk/core/auto_coder_core.py +484 -267
- autocoder/sdk/core/bridge.py +298 -118
- 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-0.1.400.dist-info/METADATA +0 -396
- auto_coder-0.1.400.dist-info/RECORD +0 -425
- auto_coder-0.1.400.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/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-0.1.400.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
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
from autocoder.commands.auto_command import (
|
|
25
|
+
CommandAutoTuner,
|
|
26
|
+
AutoCommandRequest,
|
|
27
|
+
CommandConfig,
|
|
28
|
+
MemoryConfig,
|
|
29
|
+
)
|
|
30
|
+
from autocoder.common.v2.agent.agentic_edit import AgenticEditRequest
|
|
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
|
|
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 使用。
|
|
72
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
|
+
|
|
149
|
+
|
|
150
|
+
def get_memory():
|
|
151
|
+
"""Get current memory"""
|
|
152
|
+
return load_memory()
|
|
105
153
|
|
|
106
|
-
base_persist_dir = os.path.join(project_root,".auto-coder", "plugins", "chat-auto-coder")
|
|
107
154
|
|
|
108
|
-
|
|
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,46 +742,144 @@ 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):
|
|
786
|
+
"""
|
|
787
|
+
如果项目没有初始化,则自动初始化项目
|
|
788
|
+
|
|
789
|
+
Args:
|
|
790
|
+
target_dir: 目标目录路径
|
|
791
|
+
"""
|
|
792
|
+
|
|
793
|
+
# 确保目标目录是绝对路径
|
|
794
|
+
if not os.path.isabs(target_dir):
|
|
795
|
+
target_dir = os.path.abspath(target_dir)
|
|
796
|
+
|
|
797
|
+
actions_dir = os.path.join(target_dir, "actions")
|
|
798
|
+
auto_coder_dir = os.path.join(target_dir, ".auto-coder")
|
|
799
|
+
|
|
800
|
+
# 检查是否已经初始化
|
|
801
|
+
if os.path.exists(actions_dir) and os.path.exists(auto_coder_dir):
|
|
802
|
+
return # 已经初始化,无需再次初始化
|
|
803
|
+
|
|
804
|
+
printer = Printer()
|
|
805
|
+
|
|
806
|
+
try:
|
|
807
|
+
# 创建必要的目录
|
|
808
|
+
os.makedirs(actions_dir, exist_ok=True)
|
|
809
|
+
os.makedirs(auto_coder_dir, exist_ok=True)
|
|
810
|
+
|
|
811
|
+
# 导入并使用 create_actions 创建默认的 action 文件
|
|
812
|
+
from autocoder.common.command_templates import create_actions
|
|
813
|
+
|
|
814
|
+
create_actions(
|
|
815
|
+
source_dir=target_dir,
|
|
816
|
+
params={"project_type": project_type, "source_dir": target_dir},
|
|
817
|
+
)
|
|
818
|
+
|
|
819
|
+
# 初始化 git 仓库
|
|
820
|
+
try:
|
|
821
|
+
git_utils.init(target_dir)
|
|
822
|
+
except Exception as e:
|
|
823
|
+
global_logger.warning(f"Failed to initialize git repository: {e}")
|
|
824
|
+
|
|
825
|
+
# 创建或更新 .gitignore 文件
|
|
826
|
+
gitignore_path = os.path.join(target_dir, ".gitignore")
|
|
827
|
+
gitignore_entries = [
|
|
828
|
+
".auto-coder/",
|
|
829
|
+
"/actions/",
|
|
830
|
+
"/output.txt",
|
|
831
|
+
".autocoderrules",
|
|
832
|
+
".autocodertools",
|
|
833
|
+
".autocodercommands",
|
|
834
|
+
".autocoderagents",
|
|
835
|
+
".autocoderlinters",
|
|
836
|
+
]
|
|
837
|
+
|
|
838
|
+
try:
|
|
839
|
+
# 读取现有的 .gitignore 内容
|
|
840
|
+
existing_entries = set()
|
|
841
|
+
if os.path.exists(gitignore_path):
|
|
842
|
+
with open(gitignore_path, "r", encoding="utf-8") as f:
|
|
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}")
|
|
856
|
+
except Exception as e:
|
|
857
|
+
global_logger.warning(f"Failed to update .gitignore: {e}")
|
|
858
|
+
|
|
859
|
+
# 创建 .autocoderignore 文件
|
|
860
|
+
try:
|
|
861
|
+
autocoderignore_path = os.path.join(target_dir, ".autocoderignore")
|
|
862
|
+
if not os.path.exists(autocoderignore_path):
|
|
863
|
+
autocoderignore_content = "target\n"
|
|
864
|
+
with open(autocoderignore_path, "w", encoding="utf-8") as f:
|
|
865
|
+
f.write(autocoderignore_content)
|
|
866
|
+
except Exception as e:
|
|
867
|
+
global_logger.warning(f"Failed to create .autocoderignore: {e}")
|
|
868
|
+
|
|
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
|
+
|
|
874
|
+
except Exception as e:
|
|
875
|
+
global_logger.error(f"Failed to initialize project in {target_dir}: {e}")
|
|
876
|
+
printer.print_in_terminal("init_project_error", style="red", error=str(e))
|
|
877
|
+
|
|
878
|
+
|
|
840
879
|
def _create_pull_request(commit_result, original_query: str, llm):
|
|
841
880
|
"""
|
|
842
881
|
创建 Pull Request
|
|
843
|
-
|
|
882
|
+
|
|
844
883
|
Args:
|
|
845
884
|
commit_result: 提交结果对象
|
|
846
885
|
original_query: 原始查询
|
|
@@ -848,76 +887,92 @@ def _create_pull_request(commit_result, original_query: str, llm):
|
|
|
848
887
|
"""
|
|
849
888
|
printer = Printer()
|
|
850
889
|
console = Console()
|
|
851
|
-
|
|
890
|
+
|
|
852
891
|
try:
|
|
853
892
|
# 检查是否安装了 gh CLI
|
|
854
893
|
gh_check = subprocess.run(["gh", "--version"], capture_output=True, text=True)
|
|
855
894
|
if gh_check.returncode != 0:
|
|
856
895
|
printer.print_in_terminal("pr_gh_not_installed", style="red")
|
|
857
896
|
return
|
|
858
|
-
|
|
897
|
+
|
|
859
898
|
# 检查是否已经登录 GitHub
|
|
860
|
-
auth_check = subprocess.run(
|
|
899
|
+
auth_check = subprocess.run(
|
|
900
|
+
["gh", "auth", "status"], capture_output=True, text=True
|
|
901
|
+
)
|
|
861
902
|
if auth_check.returncode != 0:
|
|
862
903
|
printer.print_in_terminal("pr_gh_not_authenticated", style="red")
|
|
863
904
|
return
|
|
864
|
-
|
|
905
|
+
|
|
865
906
|
# 获取当前分支名
|
|
866
907
|
repo = git.Repo(".")
|
|
867
908
|
current_branch = repo.active_branch.name
|
|
868
|
-
|
|
909
|
+
|
|
869
910
|
# 如果在 main/master 分支,创建新分支
|
|
870
911
|
if current_branch in ["main", "master"]:
|
|
871
912
|
# 生成新分支名
|
|
872
913
|
import re
|
|
873
|
-
|
|
914
|
+
|
|
915
|
+
branch_name = re.sub(r"[^a-zA-Z0-9\-_]", "-", original_query.lower())
|
|
874
916
|
branch_name = f"auto-coder-{branch_name[:30]}-{int(time.time())}"
|
|
875
|
-
|
|
917
|
+
|
|
876
918
|
# 创建并切换到新分支
|
|
877
919
|
new_branch = repo.create_head(branch_name)
|
|
878
920
|
new_branch.checkout()
|
|
879
921
|
current_branch = branch_name
|
|
880
|
-
|
|
881
|
-
printer.print_in_terminal(
|
|
882
|
-
|
|
922
|
+
|
|
923
|
+
printer.print_in_terminal(
|
|
924
|
+
"pr_created_branch", style="blue", branch=branch_name
|
|
925
|
+
)
|
|
926
|
+
|
|
883
927
|
# 推送当前分支到远程
|
|
884
928
|
try:
|
|
885
929
|
origin = repo.remotes.origin
|
|
886
930
|
origin.push(current_branch)
|
|
887
|
-
printer.print_in_terminal(
|
|
931
|
+
printer.print_in_terminal(
|
|
932
|
+
"pr_pushed_branch", style="blue", branch=current_branch
|
|
933
|
+
)
|
|
888
934
|
except Exception as e:
|
|
889
935
|
printer.print_in_terminal("pr_push_failed", style="red", error=str(e))
|
|
890
936
|
return
|
|
891
|
-
|
|
937
|
+
|
|
892
938
|
# 生成 PR 标题和描述
|
|
893
939
|
pr_title, pr_body = _generate_pr_content(commit_result, original_query, llm)
|
|
894
|
-
|
|
940
|
+
|
|
895
941
|
# 创建 PR
|
|
896
942
|
pr_cmd = [
|
|
897
|
-
"gh",
|
|
898
|
-
"
|
|
899
|
-
"
|
|
900
|
-
"--
|
|
943
|
+
"gh",
|
|
944
|
+
"pr",
|
|
945
|
+
"create",
|
|
946
|
+
"--title",
|
|
947
|
+
pr_title,
|
|
948
|
+
"--body",
|
|
949
|
+
pr_body,
|
|
950
|
+
"--head",
|
|
951
|
+
current_branch,
|
|
901
952
|
]
|
|
902
|
-
|
|
953
|
+
|
|
903
954
|
pr_result = subprocess.run(pr_cmd, capture_output=True, text=True)
|
|
904
|
-
|
|
955
|
+
|
|
905
956
|
if pr_result.returncode == 0:
|
|
906
957
|
pr_url = pr_result.stdout.strip()
|
|
907
958
|
printer.print_in_terminal("pr_created_success", style="green", url=pr_url)
|
|
908
|
-
|
|
959
|
+
|
|
909
960
|
# 显示 PR 信息
|
|
910
|
-
console.print(
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
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
|
+
)
|
|
918
971
|
else:
|
|
919
|
-
printer.print_in_terminal(
|
|
920
|
-
|
|
972
|
+
printer.print_in_terminal(
|
|
973
|
+
"pr_creation_failed", style="red", error=pr_result.stderr
|
|
974
|
+
)
|
|
975
|
+
|
|
921
976
|
except Exception as e:
|
|
922
977
|
printer.print_in_terminal("pr_creation_error", style="red", error=str(e))
|
|
923
978
|
|
|
@@ -926,22 +981,22 @@ def _create_pull_request(commit_result, original_query: str, llm):
|
|
|
926
981
|
def _generate_pr_content(commit_result, original_query: str, llm) -> tuple:
|
|
927
982
|
"""
|
|
928
983
|
生成 PR 标题和描述
|
|
929
|
-
|
|
984
|
+
|
|
930
985
|
根据提交信息和原始查询生成合适的 PR 标题和描述。
|
|
931
|
-
|
|
986
|
+
|
|
932
987
|
Args:
|
|
933
988
|
commit_result: 提交结果,包含 commit_message 和 changed_files
|
|
934
989
|
original_query: 用户的原始查询请求
|
|
935
|
-
|
|
990
|
+
|
|
936
991
|
Returns:
|
|
937
992
|
tuple: (pr_title, pr_body) PR标题和描述内容
|
|
938
|
-
|
|
993
|
+
|
|
939
994
|
请生成简洁明了的 PR 标题(不超过72字符)和详细的描述内容。
|
|
940
995
|
标题应该概括主要变更,描述应该包含:
|
|
941
996
|
1. 变更的背景和目的
|
|
942
997
|
2. 主要修改内容
|
|
943
998
|
3. 影响的文件(如果有的话)
|
|
944
|
-
|
|
999
|
+
|
|
945
1000
|
提交信息:{{ commit_result.commit_message }}
|
|
946
1001
|
原始需求:{{ original_query }}
|
|
947
1002
|
{% if commit_result.changed_files %}
|
|
@@ -951,7 +1006,7 @@ def _generate_pr_content(commit_result, original_query: str, llm) -> tuple:
|
|
|
951
1006
|
{% endfor %}
|
|
952
1007
|
{% endif %}
|
|
953
1008
|
"""
|
|
954
|
-
|
|
1009
|
+
|
|
955
1010
|
# 这个函数会被 byzerllm 装饰器处理,返回 LLM 生成的内容
|
|
956
1011
|
# 实际实现会在运行时由装饰器处理
|
|
957
1012
|
pass
|
|
@@ -979,14 +1034,14 @@ def _generate_pr_content(commit_result, original_query: str, llm):
|
|
|
979
1034
|
TITLE: [标题内容]
|
|
980
1035
|
BODY: [描述内容]
|
|
981
1036
|
"""
|
|
982
|
-
|
|
1037
|
+
|
|
983
1038
|
response = llm.chat([{"role": "user", "content": prompt}])
|
|
984
|
-
|
|
1039
|
+
|
|
985
1040
|
# 解析响应
|
|
986
|
-
lines = response.split(
|
|
1041
|
+
lines = response.split("\n")
|
|
987
1042
|
title = ""
|
|
988
1043
|
body = ""
|
|
989
|
-
|
|
1044
|
+
|
|
990
1045
|
for line in lines:
|
|
991
1046
|
if line.startswith("TITLE:"):
|
|
992
1047
|
title = line.replace("TITLE:", "").strip()
|
|
@@ -994,15 +1049,15 @@ BODY: [描述内容]
|
|
|
994
1049
|
body = line.replace("BODY:", "").strip()
|
|
995
1050
|
elif body: # 如果已经开始收集 body,继续添加后续行
|
|
996
1051
|
body += "\n" + line
|
|
997
|
-
|
|
1052
|
+
|
|
998
1053
|
# 如果解析失败,使用默认值
|
|
999
1054
|
if not title:
|
|
1000
1055
|
title = f"Auto-coder: {original_query[:50]}..."
|
|
1001
1056
|
if not body:
|
|
1002
1057
|
body = f"This PR was automatically generated by Auto-coder.\n\nOriginal request: {original_query}"
|
|
1003
|
-
|
|
1058
|
+
|
|
1004
1059
|
return title, body
|
|
1005
|
-
|
|
1060
|
+
|
|
1006
1061
|
except Exception as e:
|
|
1007
1062
|
# 如果 LLM 生成失败,使用默认值
|
|
1008
1063
|
title = f"Auto-coder: {original_query[:50]}..."
|
|
@@ -1011,351 +1066,34 @@ BODY: [描述内容]
|
|
|
1011
1066
|
|
|
1012
1067
|
|
|
1013
1068
|
def add_files(args: List[str]):
|
|
1069
|
+
"""
|
|
1070
|
+
处理文件添加命令,使用 AddFilesHandler 进行统一处理
|
|
1014
1071
|
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
memory["current_files"]["groups_info"] = {}
|
|
1020
|
-
if "current_groups" not in memory["current_files"]:
|
|
1021
|
-
memory["current_files"]["current_groups"] = []
|
|
1022
|
-
groups = memory["current_files"]["groups"]
|
|
1023
|
-
groups_info = memory["current_files"]["groups_info"]
|
|
1024
|
-
|
|
1025
|
-
console = Console()
|
|
1026
|
-
printer = Printer()
|
|
1027
|
-
|
|
1028
|
-
if not args:
|
|
1029
|
-
printer.print_in_terminal("add_files_no_args", style="red")
|
|
1030
|
-
result_manager.append(content=printer.get_message_from_key("add_files_no_args"),
|
|
1031
|
-
meta={"action": "add_files","success":False, "input":{ "args": args}})
|
|
1032
|
-
return
|
|
1033
|
-
|
|
1034
|
-
if args[0] == "/refresh":
|
|
1035
|
-
completer.refresh_files()
|
|
1036
|
-
load_memory()
|
|
1037
|
-
console.print(
|
|
1038
|
-
Panel("Refreshed file list.",
|
|
1039
|
-
title="Files Refreshed", border_style="green")
|
|
1040
|
-
)
|
|
1041
|
-
result_manager.append(content="Files refreshed.",
|
|
1042
|
-
meta={"action": "add_files","success":True, "input":{ "args": args}})
|
|
1043
|
-
return
|
|
1044
|
-
|
|
1045
|
-
if args[0] == "/group":
|
|
1046
|
-
if len(args) == 1 or (len(args) == 2 and args[1] == "list"):
|
|
1047
|
-
if not groups:
|
|
1048
|
-
console.print(
|
|
1049
|
-
Panel("No groups defined.", title="Groups",
|
|
1050
|
-
border_style="yellow")
|
|
1051
|
-
)
|
|
1052
|
-
result_manager.append(content="No groups defined.",
|
|
1053
|
-
meta={"action": "add_files","success":False, "input":{ "args": args}})
|
|
1054
|
-
else:
|
|
1055
|
-
table = Table(
|
|
1056
|
-
title="Defined Groups",
|
|
1057
|
-
show_header=True,
|
|
1058
|
-
header_style="bold magenta",
|
|
1059
|
-
show_lines=True,
|
|
1060
|
-
)
|
|
1061
|
-
table.add_column("Group Name", style="cyan", no_wrap=True)
|
|
1062
|
-
table.add_column("Files", style="green")
|
|
1063
|
-
table.add_column("Query Prefix", style="yellow")
|
|
1064
|
-
table.add_column("Active", style="magenta")
|
|
1065
|
-
|
|
1066
|
-
for i, (group_name, files) in enumerate(groups.items()):
|
|
1067
|
-
query_prefix = groups_info.get(group_name, {}).get(
|
|
1068
|
-
"query_prefix", ""
|
|
1069
|
-
)
|
|
1070
|
-
is_active = (
|
|
1071
|
-
"✓"
|
|
1072
|
-
if group_name in memory["current_files"]["current_groups"]
|
|
1073
|
-
else ""
|
|
1074
|
-
)
|
|
1075
|
-
table.add_row(
|
|
1076
|
-
group_name,
|
|
1077
|
-
"\n".join([os.path.relpath(f, project_root)
|
|
1078
|
-
for f in files]),
|
|
1079
|
-
query_prefix,
|
|
1080
|
-
is_active,
|
|
1081
|
-
end_section=(i == len(groups) - 1),
|
|
1082
|
-
)
|
|
1083
|
-
console.print(Panel(table, border_style="blue"))
|
|
1084
|
-
result_manager.append(content="Defined groups.",
|
|
1085
|
-
meta={"action": "add_files","success":True, "input":{ "args": args}})
|
|
1086
|
-
elif len(args) >= 2 and args[1] == "/reset":
|
|
1087
|
-
memory["current_files"]["current_groups"] = []
|
|
1088
|
-
console.print(
|
|
1089
|
-
Panel(
|
|
1090
|
-
"Active group names have been reset. If you want to clear the active files, you should use the command /remove_files /all.",
|
|
1091
|
-
title="Groups Reset",
|
|
1092
|
-
border_style="green",
|
|
1093
|
-
)
|
|
1094
|
-
)
|
|
1095
|
-
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.",
|
|
1096
|
-
meta={"action": "add_files","success":True, "input":{ "args": args}})
|
|
1097
|
-
elif len(args) >= 3 and args[1] == "/add":
|
|
1098
|
-
group_name = args[2]
|
|
1099
|
-
groups[group_name] = memory["current_files"]["files"].copy()
|
|
1100
|
-
console.print(
|
|
1101
|
-
Panel(
|
|
1102
|
-
f"Added group '{group_name}' with current files.",
|
|
1103
|
-
title="Group Added",
|
|
1104
|
-
border_style="green",
|
|
1105
|
-
)
|
|
1106
|
-
)
|
|
1107
|
-
result_manager.append(content=f"Added group '{group_name}' with current files.",
|
|
1108
|
-
meta={"action": "add_files","success":True, "input":{ "args": args}})
|
|
1109
|
-
|
|
1110
|
-
elif len(args) >= 3 and args[1] == "/drop":
|
|
1111
|
-
group_name = args[2]
|
|
1112
|
-
if group_name in groups:
|
|
1113
|
-
del memory["current_files"]["groups"][group_name]
|
|
1114
|
-
if group_name in groups_info:
|
|
1115
|
-
del memory["current_files"]["groups_info"][group_name]
|
|
1116
|
-
if group_name in memory["current_files"]["current_groups"]:
|
|
1117
|
-
memory["current_files"]["current_groups"].remove(
|
|
1118
|
-
group_name)
|
|
1119
|
-
console.print(
|
|
1120
|
-
Panel(
|
|
1121
|
-
f"Dropped group '{group_name}'.",
|
|
1122
|
-
title="Group Dropped",
|
|
1123
|
-
border_style="green",
|
|
1124
|
-
)
|
|
1125
|
-
)
|
|
1126
|
-
result_manager.append(content=f"Dropped group '{group_name}'.",
|
|
1127
|
-
meta={"action": "add_files","success":True, "input":{ "args": args}})
|
|
1128
|
-
else:
|
|
1129
|
-
console.print(
|
|
1130
|
-
Panel(
|
|
1131
|
-
f"Group '{group_name}' not found.",
|
|
1132
|
-
title="Error",
|
|
1133
|
-
border_style="red",
|
|
1134
|
-
)
|
|
1135
|
-
)
|
|
1136
|
-
result_manager.append(content=f"Group '{group_name}' not found.",
|
|
1137
|
-
meta={"action": "add_files","success":False, "input":{ "args": args}})
|
|
1138
|
-
elif len(args) == 3 and args[1] == "/set":
|
|
1139
|
-
group_name = args[2]
|
|
1140
|
-
|
|
1141
|
-
def multiline_edit():
|
|
1142
|
-
from prompt_toolkit.lexers import PygmentsLexer
|
|
1143
|
-
from pygments.lexers.markup import MarkdownLexer
|
|
1144
|
-
from prompt_toolkit.formatted_text import HTML
|
|
1145
|
-
from prompt_toolkit.shortcuts import print_formatted_text
|
|
1146
|
-
|
|
1147
|
-
style = Style.from_dict(
|
|
1148
|
-
{
|
|
1149
|
-
"dialog": "bg:#88ff88",
|
|
1150
|
-
"dialog frame.label": "bg:#ffffff #000000",
|
|
1151
|
-
"dialog.body": "bg:#000000 #00ff00",
|
|
1152
|
-
"dialog shadow": "bg:#00aa00",
|
|
1153
|
-
}
|
|
1154
|
-
)
|
|
1155
|
-
|
|
1156
|
-
print_formatted_text(
|
|
1157
|
-
HTML(
|
|
1158
|
-
"<b>Type Atom Group Desc (Prese [Esc] + [Enter] to finish.)</b><br/>"
|
|
1159
|
-
)
|
|
1160
|
-
)
|
|
1161
|
-
text = prompt(
|
|
1162
|
-
HTML("<ansicyan>║</ansicyan> "),
|
|
1163
|
-
multiline=True,
|
|
1164
|
-
lexer=PygmentsLexer(MarkdownLexer),
|
|
1165
|
-
style=style,
|
|
1166
|
-
wrap_lines=True,
|
|
1167
|
-
prompt_continuation=HTML("<ansicyan>║</ansicyan> "),
|
|
1168
|
-
rprompt=HTML("<ansicyan>║</ansicyan>"),
|
|
1169
|
-
)
|
|
1170
|
-
return text
|
|
1171
|
-
|
|
1172
|
-
query_prefix = multiline_edit()
|
|
1173
|
-
if group_name in groups:
|
|
1174
|
-
groups_info[group_name] = {"query_prefix": query_prefix}
|
|
1175
|
-
console.print(
|
|
1176
|
-
Panel(
|
|
1177
|
-
f"Set Atom Group Desc for group '{group_name}'.",
|
|
1178
|
-
title="Group Info Updated",
|
|
1179
|
-
border_style="green",
|
|
1180
|
-
)
|
|
1181
|
-
)
|
|
1182
|
-
else:
|
|
1183
|
-
console.print(
|
|
1184
|
-
Panel(
|
|
1185
|
-
f"Group '{group_name}' not found.",
|
|
1186
|
-
title="Error",
|
|
1187
|
-
border_style="red",
|
|
1188
|
-
)
|
|
1189
|
-
)
|
|
1190
|
-
elif len(args) >= 2:
|
|
1191
|
-
# 支持多个组的合并,允许组名之间使用逗号或空格分隔
|
|
1192
|
-
group_names = " ".join(args[1:]).replace(",", " ").split()
|
|
1193
|
-
merged_files = set()
|
|
1194
|
-
missing_groups = []
|
|
1195
|
-
for group_name in group_names:
|
|
1196
|
-
if group_name in groups:
|
|
1197
|
-
merged_files.update(groups[group_name])
|
|
1198
|
-
else:
|
|
1199
|
-
missing_groups.append(group_name)
|
|
1200
|
-
|
|
1201
|
-
if missing_groups:
|
|
1202
|
-
console.print(
|
|
1203
|
-
Panel(
|
|
1204
|
-
f"Group(s) not found: {', '.join(missing_groups)}",
|
|
1205
|
-
title="Error",
|
|
1206
|
-
border_style="red",
|
|
1207
|
-
)
|
|
1208
|
-
)
|
|
1209
|
-
result_manager.append(content=f"Group(s) not found: {', '.join(missing_groups)}",
|
|
1210
|
-
meta={"action": "add_files","success":False, "input":{ "args": args}})
|
|
1211
|
-
|
|
1212
|
-
if merged_files:
|
|
1213
|
-
memory["current_files"]["files"] = list(merged_files)
|
|
1214
|
-
memory["current_files"]["current_groups"] = [
|
|
1215
|
-
name for name in group_names if name in groups
|
|
1216
|
-
]
|
|
1217
|
-
console.print(
|
|
1218
|
-
Panel(
|
|
1219
|
-
f"Merged files from groups: {', '.join(group_names)}",
|
|
1220
|
-
title="Files Merged",
|
|
1221
|
-
border_style="green",
|
|
1222
|
-
)
|
|
1223
|
-
)
|
|
1224
|
-
table = Table(
|
|
1225
|
-
title="Current Files",
|
|
1226
|
-
show_header=True,
|
|
1227
|
-
header_style="bold magenta",
|
|
1228
|
-
show_lines=True, # 这会在每行之间添加分割线
|
|
1229
|
-
)
|
|
1230
|
-
table.add_column("File", style="green")
|
|
1231
|
-
for i, f in enumerate(memory["current_files"]["files"]):
|
|
1232
|
-
table.add_row(
|
|
1233
|
-
os.path.relpath(f, project_root),
|
|
1234
|
-
end_section=(
|
|
1235
|
-
i == len(memory["current_files"]["files"]) - 1
|
|
1236
|
-
), # 在最后一行之后不添加分割线
|
|
1237
|
-
)
|
|
1238
|
-
console.print(Panel(table, border_style="blue"))
|
|
1239
|
-
console.print(
|
|
1240
|
-
Panel(
|
|
1241
|
-
f"Active groups: {', '.join(memory['current_files']['current_groups'])}",
|
|
1242
|
-
title="Active Groups",
|
|
1243
|
-
border_style="green",
|
|
1244
|
-
)
|
|
1245
|
-
)
|
|
1246
|
-
result_manager.append(content=f"Active groups: {', '.join(memory['current_files']['current_groups'])}",
|
|
1247
|
-
meta={"action": "add_files","success":True, "input":{ "args": args}})
|
|
1248
|
-
elif not missing_groups:
|
|
1249
|
-
console.print(
|
|
1250
|
-
Panel(
|
|
1251
|
-
"No files in the specified groups.",
|
|
1252
|
-
title="No Files Added",
|
|
1253
|
-
border_style="yellow",
|
|
1254
|
-
)
|
|
1255
|
-
)
|
|
1256
|
-
result_manager.append(content="No files in the specified groups.",
|
|
1257
|
-
meta={"action": "add_files","success":False, "input":{ "args": args}})
|
|
1258
|
-
else:
|
|
1259
|
-
existing_files = memory["current_files"]["files"]
|
|
1260
|
-
matched_files = find_files_in_project(args)
|
|
1261
|
-
|
|
1262
|
-
files_to_add = [f for f in matched_files if f not in existing_files]
|
|
1263
|
-
if files_to_add:
|
|
1264
|
-
memory["current_files"]["files"].extend(files_to_add)
|
|
1265
|
-
table = Table(
|
|
1266
|
-
title=get_message("add_files_added_files"),
|
|
1267
|
-
show_header=True,
|
|
1268
|
-
header_style="bold magenta",
|
|
1269
|
-
show_lines=True, # 这会在每行之间添加分割线
|
|
1270
|
-
)
|
|
1271
|
-
table.add_column("File", style="green")
|
|
1272
|
-
for i, f in enumerate(files_to_add):
|
|
1273
|
-
table.add_row(
|
|
1274
|
-
os.path.relpath(f, project_root),
|
|
1275
|
-
end_section=(
|
|
1276
|
-
i == len(files_to_add) - 1
|
|
1277
|
-
), # 在最后一行之后不添加分割线
|
|
1278
|
-
)
|
|
1279
|
-
console.print(Panel(table, border_style="green"))
|
|
1280
|
-
result_manager.append(content=f"Added files: {', '.join(files_to_add)}",
|
|
1281
|
-
meta={"action": "add_files","success":True, "input":{ "args": args}})
|
|
1282
|
-
else:
|
|
1283
|
-
printer.print_in_terminal("add_files_matched", style="yellow")
|
|
1284
|
-
result_manager.append(content=f"No files matched.",
|
|
1285
|
-
meta={"action": "add_files","success":False, "input":{ "args": args}})
|
|
1072
|
+
Args:
|
|
1073
|
+
args: 命令参数列表
|
|
1074
|
+
"""
|
|
1075
|
+
from autocoder.common.file_handler import AddFilesHandler
|
|
1286
1076
|
|
|
1287
|
-
|
|
1077
|
+
handler = AddFilesHandler()
|
|
1078
|
+
handler.handle_add_files_command(args)
|
|
1288
1079
|
|
|
1289
1080
|
|
|
1290
1081
|
def remove_files(file_names: List[str]):
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
result_manager = ResultManager()
|
|
1082
|
+
"""
|
|
1083
|
+
处理文件删除命令,使用 RemoveFilesHandler 进行统一处理
|
|
1294
1084
|
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
result_manager.append(content="All files removed.",
|
|
1300
|
-
meta={"action": "remove_files","success":True, "input":{ "file_names": file_names}})
|
|
1301
|
-
else:
|
|
1302
|
-
files_to_remove = set()
|
|
1303
|
-
current_files_abs = memory["current_files"]["files"]
|
|
1304
|
-
|
|
1305
|
-
for pattern in file_names:
|
|
1306
|
-
pattern = pattern.strip() # Remove leading/trailing whitespace
|
|
1307
|
-
if not pattern:
|
|
1308
|
-
continue
|
|
1309
|
-
|
|
1310
|
-
is_wildcard = "*" in pattern or "?" in pattern
|
|
1311
|
-
|
|
1312
|
-
for file_path_abs in current_files_abs:
|
|
1313
|
-
relative_path = os.path.relpath(file_path_abs, project_root)
|
|
1314
|
-
basename = os.path.basename(file_path_abs)
|
|
1315
|
-
|
|
1316
|
-
matched = False
|
|
1317
|
-
if is_wildcard:
|
|
1318
|
-
# Match pattern against relative path or basename
|
|
1319
|
-
if fnmatch.fnmatch(relative_path, pattern) or fnmatch.fnmatch(basename, pattern):
|
|
1320
|
-
matched = True
|
|
1321
|
-
else:
|
|
1322
|
-
# Exact match against relative path, absolute path, or basename
|
|
1323
|
-
if relative_path == pattern or file_path_abs == pattern or basename == pattern:
|
|
1324
|
-
matched = True
|
|
1325
|
-
|
|
1326
|
-
if matched:
|
|
1327
|
-
files_to_remove.add(file_path_abs)
|
|
1328
|
-
|
|
1329
|
-
removed_files_list = list(files_to_remove)
|
|
1330
|
-
if removed_files_list:
|
|
1331
|
-
# Update memory by filtering out the files to remove
|
|
1332
|
-
memory["current_files"]["files"] = [
|
|
1333
|
-
f for f in current_files_abs if f not in files_to_remove
|
|
1334
|
-
]
|
|
1085
|
+
Args:
|
|
1086
|
+
file_names: 文件名列表或模式列表
|
|
1087
|
+
"""
|
|
1088
|
+
from autocoder.common.file_handler import RemoveFilesHandler
|
|
1335
1089
|
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
header_style="bold magenta"
|
|
1339
|
-
)
|
|
1340
|
-
table.add_column(printer.get_message_from_key("file_column_title"), style="green")
|
|
1341
|
-
for f in removed_files_list:
|
|
1342
|
-
table.add_row(os.path.relpath(f, project_root))
|
|
1090
|
+
handler = RemoveFilesHandler()
|
|
1091
|
+
handler.handle_remove_files_command(file_names)
|
|
1343
1092
|
|
|
1344
|
-
console = Console()
|
|
1345
|
-
console.print(
|
|
1346
|
-
Panel(table, border_style="green",
|
|
1347
|
-
title=printer.get_message_from_key("files_removed")))
|
|
1348
|
-
result_manager.append(content=f"Removed files: {', '.join(removed_files_list)}",
|
|
1349
|
-
meta={"action": "remove_files","success":True, "input":{ "file_names": file_names}})
|
|
1350
|
-
else:
|
|
1351
|
-
printer.print_in_terminal("remove_files_none", style="yellow")
|
|
1352
|
-
result_manager.append(content=printer.get_message_from_key("remove_files_none"),
|
|
1353
|
-
meta={"action": "remove_files","success":False, "input":{ "file_names": file_names}})
|
|
1354
|
-
save_memory()
|
|
1355
1093
|
|
|
1356
|
-
@run_in_raw_thread()
|
|
1357
1094
|
def ask(query: str):
|
|
1358
|
-
|
|
1095
|
+
memory_manager = get_memory_manager()
|
|
1096
|
+
conf = memory_manager.get_all_config()
|
|
1359
1097
|
yaml_config = {
|
|
1360
1098
|
"include_file": ["./base/base.yml"],
|
|
1361
1099
|
}
|
|
@@ -1383,7 +1121,7 @@ def ask(query: str):
|
|
|
1383
1121
|
|
|
1384
1122
|
execute_file = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
1385
1123
|
|
|
1386
|
-
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:
|
|
1387
1125
|
f.write(yaml_content)
|
|
1388
1126
|
|
|
1389
1127
|
def execute_ask():
|
|
@@ -1398,50 +1136,27 @@ def ask(query: str):
|
|
|
1398
1136
|
def get_llm_friendly_package_docs(
|
|
1399
1137
|
package_name: Optional[str] = None, return_paths: bool = False
|
|
1400
1138
|
) -> List[str]:
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
return
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
if os.path.isdir(username_path):
|
|
1416
|
-
for lib_name in os.listdir(username_path):
|
|
1417
|
-
lib_path = os.path.join(username_path, lib_name)
|
|
1418
|
-
if (
|
|
1419
|
-
os.path.isdir(lib_path)
|
|
1420
|
-
and (
|
|
1421
|
-
package_name is None
|
|
1422
|
-
or lib_name == package_name
|
|
1423
|
-
or package_name == os.path.join(username, lib_name)
|
|
1424
|
-
)
|
|
1425
|
-
and lib_name in libs
|
|
1426
|
-
):
|
|
1427
|
-
for root, _, files in os.walk(lib_path):
|
|
1428
|
-
for file in files:
|
|
1429
|
-
if file.endswith(".md"):
|
|
1430
|
-
file_path = os.path.join(root, file)
|
|
1431
|
-
if return_paths:
|
|
1432
|
-
docs.append(file_path)
|
|
1433
|
-
else:
|
|
1434
|
-
with open(file_path, "r",encoding="utf-8") as f:
|
|
1435
|
-
docs.append(f.read())
|
|
1436
|
-
|
|
1437
|
-
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)
|
|
1438
1153
|
|
|
1439
1154
|
|
|
1440
1155
|
def convert_yaml_to_config(yaml_file: str):
|
|
1441
1156
|
from autocoder.auto_coder import AutoCoderArgs, load_include_files, Template
|
|
1442
1157
|
|
|
1443
1158
|
args = AutoCoderArgs()
|
|
1444
|
-
with open(yaml_file, "r",encoding="utf-8") as f:
|
|
1159
|
+
with open(yaml_file, "r", encoding="utf-8") as f:
|
|
1445
1160
|
config = yaml.safe_load(f)
|
|
1446
1161
|
config = load_include_files(config, yaml_file)
|
|
1447
1162
|
for key, value in config.items():
|
|
@@ -1453,150 +1168,22 @@ def convert_yaml_to_config(yaml_file: str):
|
|
|
1453
1168
|
setattr(args, key, value)
|
|
1454
1169
|
return args
|
|
1455
1170
|
|
|
1456
|
-
@run_in_raw_thread()
|
|
1457
|
-
def mcp(query: str):
|
|
1458
|
-
query = query.strip()
|
|
1459
|
-
mcp_server = get_mcp_server()
|
|
1460
|
-
printer = Printer()
|
|
1461
|
-
|
|
1462
|
-
# Handle remove command
|
|
1463
|
-
if query.startswith("/remove"):
|
|
1464
|
-
server_name = query.replace("/remove", "", 1).strip()
|
|
1465
|
-
response = mcp_server.send_request(
|
|
1466
|
-
McpRemoveRequest(server_name=server_name))
|
|
1467
|
-
if response.error:
|
|
1468
|
-
printer.print_in_terminal("mcp_remove_error", style="red", error=response.error)
|
|
1469
|
-
else:
|
|
1470
|
-
printer.print_in_terminal("mcp_remove_success", style="green", result=response.result)
|
|
1471
|
-
return
|
|
1472
|
-
|
|
1473
|
-
# Handle list command
|
|
1474
|
-
if query.startswith("/list_running"):
|
|
1475
|
-
response = mcp_server.send_request(McpListRunningRequest())
|
|
1476
|
-
if response.error:
|
|
1477
|
-
printer.print_in_terminal("mcp_list_running_error", style="red", error=response.error)
|
|
1478
|
-
else:
|
|
1479
|
-
printer.print_in_terminal("mcp_list_running_title")
|
|
1480
|
-
printer.print_str_in_terminal(response.result)
|
|
1481
|
-
return
|
|
1482
|
-
|
|
1483
|
-
# Handle list command
|
|
1484
|
-
if query.startswith("/list"):
|
|
1485
|
-
response = mcp_server.send_request(McpListRequest())
|
|
1486
|
-
if response.error:
|
|
1487
|
-
printer.print_in_terminal("mcp_list_builtin_error", style="red", error=response.error)
|
|
1488
|
-
else:
|
|
1489
|
-
printer.print_in_terminal("mcp_list_builtin_title")
|
|
1490
|
-
printer.print_str_in_terminal(response.result)
|
|
1491
|
-
return
|
|
1492
|
-
|
|
1493
|
-
# Handle refresh command
|
|
1494
|
-
if query.startswith("/refresh"):
|
|
1495
|
-
server_name = query.replace("/refresh", "", 1).strip()
|
|
1496
|
-
response = mcp_server.send_request(McpRefreshRequest(name=server_name or None))
|
|
1497
|
-
if response.error:
|
|
1498
|
-
printer.print_in_terminal("mcp_refresh_error", style="red", error=response.error)
|
|
1499
|
-
else:
|
|
1500
|
-
printer.print_in_terminal("mcp_refresh_success", style="green")
|
|
1501
|
-
return
|
|
1502
|
-
|
|
1503
|
-
# Handle add command
|
|
1504
|
-
if query.startswith("/add"):
|
|
1505
|
-
query = query.replace("/add", "", 1).strip()
|
|
1506
|
-
request = McpInstallRequest(server_name_or_config=query)
|
|
1507
|
-
response = mcp_server.send_request(request)
|
|
1508
|
-
|
|
1509
|
-
if response.error:
|
|
1510
|
-
printer.print_in_terminal("mcp_install_error", style="red", error=response.error)
|
|
1511
|
-
else:
|
|
1512
|
-
printer.print_in_terminal("mcp_install_success", style="green", result=response.result)
|
|
1513
|
-
return
|
|
1514
|
-
|
|
1515
|
-
# Handle default query
|
|
1516
|
-
conf = memory.get("conf", {})
|
|
1517
|
-
yaml_config = {
|
|
1518
|
-
"include_file": ["./base/base.yml"],
|
|
1519
|
-
"auto_merge": conf.get("auto_merge", "editblock"),
|
|
1520
|
-
"human_as_model": conf.get("human_as_model", "false") == "true",
|
|
1521
|
-
"skip_build_index": conf.get("skip_build_index", "true") == "true",
|
|
1522
|
-
"skip_confirm": conf.get("skip_confirm", "true") == "true",
|
|
1523
|
-
"silence": conf.get("silence", "true") == "true",
|
|
1524
|
-
"include_project_structure": conf.get("include_project_structure", "true")
|
|
1525
|
-
== "true",
|
|
1526
|
-
"exclude_files": memory.get("exclude_files", []),
|
|
1527
|
-
}
|
|
1528
|
-
for key, value in conf.items():
|
|
1529
|
-
converted_value = convert_config_value(key, value)
|
|
1530
|
-
if converted_value is not None:
|
|
1531
|
-
yaml_config[key] = converted_value
|
|
1532
1171
|
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
f.write(convert_yaml_config_to_str(yaml_config=yaml_config))
|
|
1537
|
-
args = convert_yaml_to_config(temp_yaml)
|
|
1538
|
-
finally:
|
|
1539
|
-
if os.path.exists(temp_yaml):
|
|
1540
|
-
os.remove(temp_yaml)
|
|
1541
|
-
|
|
1542
|
-
mcp_server = get_mcp_server()
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
if query.startswith("/info"):
|
|
1546
|
-
response = mcp_server.send_request(McpServerInfoRequest(
|
|
1547
|
-
model=args.inference_model or args.model,
|
|
1548
|
-
product_mode=args.product_mode
|
|
1549
|
-
))
|
|
1550
|
-
if response.error:
|
|
1551
|
-
printer.print_in_terminal("mcp_server_info_error", style="red", error=response.error)
|
|
1552
|
-
else:
|
|
1553
|
-
printer.print_in_terminal("mcp_server_info_title")
|
|
1554
|
-
printer.print_str_in_terminal(response.result)
|
|
1555
|
-
return
|
|
1556
|
-
|
|
1557
|
-
response = mcp_server.send_request(
|
|
1558
|
-
McpRequest(
|
|
1559
|
-
query=query,
|
|
1560
|
-
model=args.inference_model or args.model,
|
|
1561
|
-
product_mode=args.product_mode
|
|
1562
|
-
)
|
|
1563
|
-
)
|
|
1172
|
+
def mcp(query: str):
|
|
1173
|
+
"""
|
|
1174
|
+
处理MCP命令,使用 McpHandler 进行统一处理
|
|
1564
1175
|
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
panel_options={
|
|
1570
|
-
"title": printer.get_message_from_key("mcp_error_title"),
|
|
1571
|
-
"border_style": "red"
|
|
1572
|
-
}
|
|
1573
|
-
)
|
|
1574
|
-
else:
|
|
1575
|
-
# Save conversation
|
|
1576
|
-
mcp_dir = os.path.join(".auto-coder", "mcp", "conversations")
|
|
1577
|
-
os.makedirs(mcp_dir, exist_ok=True)
|
|
1578
|
-
timestamp = str(int(time.time()))
|
|
1579
|
-
file_path = os.path.join(mcp_dir, f"{timestamp}.md")
|
|
1176
|
+
Args:
|
|
1177
|
+
query: 查询字符串
|
|
1178
|
+
"""
|
|
1179
|
+
from autocoder.common.file_handler import McpHandler
|
|
1580
1180
|
|
|
1581
|
-
|
|
1582
|
-
|
|
1181
|
+
handler = McpHandler()
|
|
1182
|
+
handler.handle_mcp_command(query)
|
|
1583
1183
|
|
|
1584
|
-
# Save to file
|
|
1585
|
-
with open(file_path, "w", encoding="utf-8") as f:
|
|
1586
|
-
f.write(markdown_content)
|
|
1587
1184
|
|
|
1588
|
-
console = Console()
|
|
1589
|
-
console.print(
|
|
1590
|
-
Panel(
|
|
1591
|
-
Markdown(markdown_content, justify="left"),
|
|
1592
|
-
title=printer.get_message_from_key('mcp_response_title'),
|
|
1593
|
-
border_style="green"
|
|
1594
|
-
)
|
|
1595
|
-
)
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
@run_in_raw_thread()
|
|
1599
1185
|
def code_next(query: str):
|
|
1186
|
+
memory = get_current_memory()
|
|
1600
1187
|
conf = memory.get("conf", {})
|
|
1601
1188
|
yaml_config = {
|
|
1602
1189
|
"include_file": ["./base/base.yml"],
|
|
@@ -1605,7 +1192,7 @@ def code_next(query: str):
|
|
|
1605
1192
|
"skip_build_index": conf.get("skip_build_index", "true") == "true",
|
|
1606
1193
|
"skip_confirm": conf.get("skip_confirm", "true") == "true",
|
|
1607
1194
|
"silence": conf.get("silence", "true") == "true",
|
|
1608
|
-
"include_project_structure": conf.get("include_project_structure", "
|
|
1195
|
+
"include_project_structure": conf.get("include_project_structure", "false")
|
|
1609
1196
|
== "true",
|
|
1610
1197
|
"exclude_files": memory.get("exclude_files", []),
|
|
1611
1198
|
}
|
|
@@ -1616,7 +1203,7 @@ def code_next(query: str):
|
|
|
1616
1203
|
|
|
1617
1204
|
temp_yaml = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
1618
1205
|
try:
|
|
1619
|
-
with open(temp_yaml, "w",encoding="utf-8") as f:
|
|
1206
|
+
with open(temp_yaml, "w", encoding="utf-8") as f:
|
|
1620
1207
|
f.write(convert_yaml_config_to_str(yaml_config=yaml_config))
|
|
1621
1208
|
args = convert_yaml_to_config(temp_yaml)
|
|
1622
1209
|
finally:
|
|
@@ -1626,8 +1213,7 @@ def code_next(query: str):
|
|
|
1626
1213
|
product_mode = conf.get("product_mode", "lite")
|
|
1627
1214
|
llm = get_single_llm(args.chat_model or args.model, product_mode=product_mode)
|
|
1628
1215
|
|
|
1629
|
-
auto_guesser = AutoGuessQuery(
|
|
1630
|
-
llm=llm, project_dir=os.getcwd(), skip_diff=True)
|
|
1216
|
+
auto_guesser = AutoGuessQuery(llm=llm, project_dir=os.getcwd(), skip_diff=True)
|
|
1631
1217
|
|
|
1632
1218
|
predicted_tasks = auto_guesser.predict_next_tasks(
|
|
1633
1219
|
5, is_human_as_model=args.human_as_model
|
|
@@ -1641,25 +1227,20 @@ def code_next(query: str):
|
|
|
1641
1227
|
console = Console()
|
|
1642
1228
|
|
|
1643
1229
|
# Create main panel for all predicted tasks
|
|
1644
|
-
table = Table(show_header=True,
|
|
1645
|
-
header_style="bold magenta", show_lines=True)
|
|
1230
|
+
table = Table(show_header=True, header_style="bold magenta", show_lines=True)
|
|
1646
1231
|
table.add_column("Priority", style="cyan", width=8)
|
|
1647
|
-
table.add_column("Task Description", style="green",
|
|
1648
|
-
width=40, overflow="fold")
|
|
1232
|
+
table.add_column("Task Description", style="green", width=40, overflow="fold")
|
|
1649
1233
|
table.add_column("Files", style="yellow", width=30, overflow="fold")
|
|
1650
1234
|
table.add_column("Reason", style="blue", width=30, overflow="fold")
|
|
1651
|
-
table.add_column("Dependencies", style="magenta",
|
|
1652
|
-
width=30, overflow="fold")
|
|
1235
|
+
table.add_column("Dependencies", style="magenta", width=30, overflow="fold")
|
|
1653
1236
|
|
|
1654
1237
|
for task in predicted_tasks:
|
|
1655
1238
|
# Format file paths to be more readable
|
|
1656
|
-
file_list = "\n".join([os.path.relpath(f, os.getcwd())
|
|
1657
|
-
for f in task.urls])
|
|
1239
|
+
file_list = "\n".join([os.path.relpath(f, os.getcwd()) for f in task.urls])
|
|
1658
1240
|
|
|
1659
1241
|
# Format dependencies to be more readable
|
|
1660
1242
|
dependencies = (
|
|
1661
|
-
"\n".join(
|
|
1662
|
-
task.dependency_queries) if task.dependency_queries else "None"
|
|
1243
|
+
"\n".join(task.dependency_queries) if task.dependency_queries else "None"
|
|
1663
1244
|
)
|
|
1664
1245
|
|
|
1665
1246
|
table.add_row(
|
|
@@ -1676,260 +1257,42 @@ def code_next(query: str):
|
|
|
1676
1257
|
)
|
|
1677
1258
|
|
|
1678
1259
|
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
product_mode = conf.get("product_mode", "lite")
|
|
1683
|
-
def prepare_commit_yaml():
|
|
1684
|
-
auto_coder_main(["next", "chat_action"])
|
|
1685
|
-
|
|
1686
|
-
prepare_commit_yaml()
|
|
1687
|
-
|
|
1688
|
-
# no_diff = query.strip().startswith("/no_diff")
|
|
1689
|
-
# if no_diff:
|
|
1690
|
-
# query = query.replace("/no_diff", "", 1).strip()
|
|
1691
|
-
|
|
1692
|
-
latest_yaml_file = get_last_yaml_file("actions")
|
|
1693
|
-
|
|
1694
|
-
conf = memory.get("conf", {})
|
|
1695
|
-
current_files = memory["current_files"]["files"]
|
|
1696
|
-
execute_file = None
|
|
1697
|
-
|
|
1698
|
-
if latest_yaml_file:
|
|
1699
|
-
try:
|
|
1700
|
-
execute_file = os.path.join("actions", latest_yaml_file)
|
|
1701
|
-
yaml_config = {
|
|
1702
|
-
"include_file": ["./base/base.yml"],
|
|
1703
|
-
"auto_merge": conf.get("auto_merge", "editblock"),
|
|
1704
|
-
"human_as_model": conf.get("human_as_model", "false") == "true",
|
|
1705
|
-
"skip_build_index": conf.get("skip_build_index", "true") == "true",
|
|
1706
|
-
"skip_confirm": conf.get("skip_confirm", "true") == "true",
|
|
1707
|
-
"silence": conf.get("silence", "true") == "true",
|
|
1708
|
-
"include_project_structure": conf.get("include_project_structure", "true")
|
|
1709
|
-
== "true",
|
|
1710
|
-
}
|
|
1711
|
-
for key, value in conf.items():
|
|
1712
|
-
converted_value = convert_config_value(key, value)
|
|
1713
|
-
if converted_value is not None:
|
|
1714
|
-
yaml_config[key] = converted_value
|
|
1715
|
-
|
|
1716
|
-
yaml_config["urls"] = current_files + get_llm_friendly_package_docs(
|
|
1717
|
-
return_paths=True
|
|
1718
|
-
)
|
|
1719
|
-
|
|
1720
|
-
if conf.get("enable_global_memory", "false") in ["true", "True",True]:
|
|
1721
|
-
yaml_config["urls"] += get_global_memory_file_paths()
|
|
1722
|
-
|
|
1723
|
-
# 临时保存yaml文件,然后读取yaml文件,转换为args
|
|
1724
|
-
temp_yaml = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
1725
|
-
try:
|
|
1726
|
-
with open(temp_yaml, "w",encoding="utf-8") as f:
|
|
1727
|
-
f.write(convert_yaml_config_to_str(
|
|
1728
|
-
yaml_config=yaml_config))
|
|
1729
|
-
args = convert_yaml_to_config(temp_yaml)
|
|
1730
|
-
finally:
|
|
1731
|
-
if os.path.exists(temp_yaml):
|
|
1732
|
-
os.remove(temp_yaml)
|
|
1733
|
-
|
|
1734
|
-
target_model = args.commit_model or args.model
|
|
1735
|
-
llm = get_single_llm(target_model, product_mode)
|
|
1736
|
-
printer = Printer()
|
|
1737
|
-
printer.print_in_terminal("commit_generating", style="yellow", model_name=target_model)
|
|
1738
|
-
commit_message = ""
|
|
1739
|
-
|
|
1740
|
-
try:
|
|
1741
|
-
uncommitted_changes = git_utils.get_uncommitted_changes(".")
|
|
1742
|
-
commit_message = git_utils.generate_commit_message.with_llm(llm).run(
|
|
1743
|
-
uncommitted_changes
|
|
1744
|
-
)
|
|
1745
|
-
# memory["conversation"].append(
|
|
1746
|
-
# {"role": "user", "content": commit_message})
|
|
1747
|
-
except Exception as e:
|
|
1748
|
-
printer.print_in_terminal("commit_failed", style="red", error=str(e), model_name=target_model)
|
|
1749
|
-
return
|
|
1750
|
-
|
|
1751
|
-
yaml_config["query"] = commit_message
|
|
1752
|
-
yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
|
|
1753
|
-
with open(os.path.join(execute_file), "w",encoding="utf-8") as f:
|
|
1754
|
-
f.write(yaml_content)
|
|
1755
|
-
|
|
1756
|
-
args.file = execute_file
|
|
1757
|
-
|
|
1758
|
-
file_name = os.path.basename(execute_file)
|
|
1759
|
-
commit_result = git_utils.commit_changes(
|
|
1760
|
-
".", f"{commit_message}\nauto_coder_{file_name}"
|
|
1761
|
-
)
|
|
1762
|
-
|
|
1763
|
-
printer = Printer()
|
|
1764
|
-
|
|
1765
|
-
action_yml_file_manager = ActionYmlFileManager(args.source_dir)
|
|
1766
|
-
action_file_name = os.path.basename(args.file)
|
|
1767
|
-
add_updated_urls = []
|
|
1768
|
-
for file in commit_result.changed_files:
|
|
1769
|
-
add_updated_urls.append(os.path.join(args.source_dir, file))
|
|
1770
|
-
|
|
1771
|
-
args.add_updated_urls = add_updated_urls
|
|
1772
|
-
update_yaml_success = action_yml_file_manager.update_yaml_field(action_file_name, "add_updated_urls", add_updated_urls)
|
|
1773
|
-
if not update_yaml_success:
|
|
1774
|
-
printer.print_in_terminal("yaml_save_error", style="red", yaml_file=action_file_name)
|
|
1775
|
-
|
|
1776
|
-
if args.enable_active_context:
|
|
1777
|
-
active_context_manager = ActiveContextManager(llm, args.source_dir)
|
|
1778
|
-
task_id = active_context_manager.process_changes(args)
|
|
1779
|
-
printer.print_in_terminal("active_context_background_task",
|
|
1780
|
-
style="blue",
|
|
1781
|
-
task_id=task_id)
|
|
1782
|
-
git_utils.print_commit_info(commit_result=commit_result)
|
|
1783
|
-
if commit_message:
|
|
1784
|
-
printer.print_in_terminal("commit_message", style="green", model_name=target_model, message=commit_message)
|
|
1785
|
-
except Exception as e:
|
|
1786
|
-
import traceback
|
|
1787
|
-
traceback.print_exc()
|
|
1788
|
-
print(f"Failed to commit: {e}")
|
|
1789
|
-
if execute_file:
|
|
1790
|
-
os.remove(execute_file)
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
@run_in_raw_thread()
|
|
1794
|
-
def coding(query: str):
|
|
1795
|
-
console = Console()
|
|
1796
|
-
is_apply = query.strip().startswith("/apply")
|
|
1797
|
-
if is_apply:
|
|
1798
|
-
query = query.replace("/apply", "", 1).strip()
|
|
1799
|
-
|
|
1800
|
-
is_next = query.strip().startswith("/next")
|
|
1801
|
-
if is_next:
|
|
1802
|
-
query = query.replace("/next", "", 1).strip()
|
|
1803
|
-
|
|
1804
|
-
if is_next:
|
|
1805
|
-
code_next(query)
|
|
1806
|
-
return
|
|
1807
|
-
|
|
1808
|
-
# memory["conversation"].append({"role": "user", "content": query})
|
|
1809
|
-
conf = memory.get("conf", {})
|
|
1810
|
-
|
|
1811
|
-
current_files = memory["current_files"]["files"]
|
|
1812
|
-
current_groups = memory["current_files"].get("current_groups", [])
|
|
1813
|
-
groups = memory["current_files"].get("groups", {})
|
|
1814
|
-
groups_info = memory["current_files"].get("groups_info", {})
|
|
1815
|
-
|
|
1816
|
-
def prepare_chat_yaml():
|
|
1817
|
-
auto_coder_main(["next", "chat_action"])
|
|
1818
|
-
|
|
1819
|
-
prepare_chat_yaml()
|
|
1820
|
-
|
|
1821
|
-
latest_yaml_file = get_last_yaml_file("actions")
|
|
1822
|
-
|
|
1823
|
-
if latest_yaml_file:
|
|
1824
|
-
yaml_config = {
|
|
1825
|
-
"include_file": ["./base/base.yml"],
|
|
1826
|
-
"auto_merge": conf.get("auto_merge", "editblock"),
|
|
1827
|
-
"human_as_model": conf.get("human_as_model", "false") == "true",
|
|
1828
|
-
"skip_build_index": conf.get("skip_build_index", "true") == "true",
|
|
1829
|
-
"skip_confirm": conf.get("skip_confirm", "true") == "true",
|
|
1830
|
-
"silence": conf.get("silence", "true") == "true",
|
|
1831
|
-
"include_project_structure": conf.get("include_project_structure", "true")
|
|
1832
|
-
== "true",
|
|
1833
|
-
"exclude_files": memory.get("exclude_files", []),
|
|
1834
|
-
}
|
|
1835
|
-
|
|
1836
|
-
yaml_config["context"] = ""
|
|
1837
|
-
yaml_config["in_code_apply"] = is_apply
|
|
1838
|
-
|
|
1839
|
-
for key, value in conf.items():
|
|
1840
|
-
converted_value = convert_config_value(key, value)
|
|
1841
|
-
if converted_value is not None:
|
|
1842
|
-
yaml_config[key] = converted_value
|
|
1260
|
+
def commit(query: Optional[str] = None):
|
|
1261
|
+
"""
|
|
1262
|
+
处理提交命令,使用 CommitHandler 进行统一处理
|
|
1843
1263
|
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1264
|
+
Args:
|
|
1265
|
+
query: 可选的提交消息或命令
|
|
1266
|
+
"""
|
|
1267
|
+
from autocoder.common.file_handler import CommitHandler
|
|
1847
1268
|
|
|
1848
|
-
|
|
1849
|
-
|
|
1269
|
+
handler = CommitHandler()
|
|
1270
|
+
handler.handle_commit_command(query)
|
|
1850
1271
|
|
|
1851
|
-
# handle image
|
|
1852
|
-
v = Image.convert_image_paths_from(query)
|
|
1853
|
-
yaml_config["query"] = v
|
|
1854
1272
|
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
for group in current_groups:
|
|
1859
|
-
group_files = groups.get(group, [])
|
|
1860
|
-
query_prefix = groups_info.get(
|
|
1861
|
-
group, {}).get("query_prefix", "")
|
|
1862
|
-
active_groups_context += f"组名: {group}\n"
|
|
1863
|
-
active_groups_context += f"文件列表:\n"
|
|
1864
|
-
for file in group_files:
|
|
1865
|
-
active_groups_context += f"- {file}\n"
|
|
1866
|
-
active_groups_context += f"组描述: {query_prefix}\n\n"
|
|
1867
|
-
|
|
1868
|
-
yaml_config["context"] = active_groups_context + "\n"
|
|
1869
|
-
|
|
1870
|
-
if is_apply:
|
|
1871
|
-
memory_dir = os.path.join(".auto-coder", "memory")
|
|
1872
|
-
os.makedirs(memory_dir, exist_ok=True)
|
|
1873
|
-
memory_file = os.path.join(memory_dir, "chat_history.json")
|
|
1874
|
-
|
|
1875
|
-
def error_message():
|
|
1876
|
-
console.print(
|
|
1877
|
-
Panel(
|
|
1878
|
-
"No chat history found to apply.",
|
|
1879
|
-
title="Chat History",
|
|
1880
|
-
expand=False,
|
|
1881
|
-
border_style="yellow",
|
|
1882
|
-
)
|
|
1883
|
-
)
|
|
1273
|
+
def coding(query: str, cancel_token=None):
|
|
1274
|
+
"""
|
|
1275
|
+
处理代码生成命令,使用 CodingHandler 进行统一处理
|
|
1884
1276
|
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
if not chat_history["ask_conversation"]:
|
|
1891
|
-
error_message()
|
|
1892
|
-
else:
|
|
1893
|
-
conversations = chat_history["ask_conversation"]
|
|
1894
|
-
|
|
1895
|
-
if conversations:
|
|
1896
|
-
yaml_config[
|
|
1897
|
-
"context"
|
|
1898
|
-
] += f"下面是我们的历史对话,参考我们的历史对话从而更好的理解需求和修改代码: \n\n<history>\n"
|
|
1899
|
-
for conv in conversations:
|
|
1900
|
-
if conv["role"] == "user":
|
|
1901
|
-
yaml_config["context"] += f"用户: {conv['content']}\n"
|
|
1902
|
-
elif conv["role"] == "assistant":
|
|
1903
|
-
yaml_config["context"] += f"你: {conv['content']}\n"
|
|
1904
|
-
yaml_config["context"] += "</history>\n"
|
|
1905
|
-
|
|
1906
|
-
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
|
|
1907
1282
|
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
f.write(yaml_content)
|
|
1283
|
+
handler = CodingHandler()
|
|
1284
|
+
handler.handle_coding_command(query, cancel_token)
|
|
1911
1285
|
|
|
1912
|
-
def execute_chat():
|
|
1913
|
-
cmd = ["--file", execute_file]
|
|
1914
|
-
auto_coder_main(cmd)
|
|
1915
|
-
result_manager = ResultManager()
|
|
1916
|
-
result_manager.append(content="", meta={"commit_message": f"auto_coder_{latest_yaml_file}","action": "coding", "input":{
|
|
1917
|
-
"query": query
|
|
1918
|
-
}})
|
|
1919
1286
|
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
print("Failed to create new YAML file.")
|
|
1287
|
+
def rules(query: str):
|
|
1288
|
+
from autocoder.chat.rules_command import handle_rules_command
|
|
1923
1289
|
|
|
1924
|
-
|
|
1290
|
+
result = handle_rules_command(query, coding_func=coding)
|
|
1291
|
+
# 只有当结果不为空时才打印,避免重复输出
|
|
1292
|
+
if result and result.strip():
|
|
1293
|
+
print(result)
|
|
1925
1294
|
completer.refresh_files()
|
|
1926
1295
|
|
|
1927
|
-
@run_in_raw_thread()
|
|
1928
|
-
def rules(query: str):
|
|
1929
|
-
from autocoder.chat.rules_command import handle_rules_command
|
|
1930
|
-
memory = get_memory()
|
|
1931
|
-
handle_rules_command(query, memory,coding_func=coding)
|
|
1932
|
-
completer.refresh_files()
|
|
1933
1296
|
|
|
1934
1297
|
@byzerllm.prompt()
|
|
1935
1298
|
def code_review(query: str) -> str:
|
|
@@ -1947,95 +1310,32 @@ def code_review(query: str) -> str:
|
|
|
1947
1310
|
如果用户的需求包含了@一个文件名 或者 @@符号, 那么重点关注这些文件或者符号(函数,类)进行上述的review。
|
|
1948
1311
|
review 过程中严格遵循上述的检查点,不要遗漏,没有发现异常的点直接跳过,只对发现的异常点,给出具体的修改后的代码。
|
|
1949
1312
|
"""
|
|
1313
|
+
return {} # type: ignore
|
|
1950
1314
|
|
|
1951
1315
|
|
|
1952
|
-
@run_in_raw_thread()
|
|
1953
1316
|
def chat(query: str):
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
yaml_config = {
|
|
1957
|
-
"include_file": ["./base/base.yml"],
|
|
1958
|
-
"include_project_structure": conf.get("include_project_structure", "true")
|
|
1959
|
-
in ["true", "True"],
|
|
1960
|
-
"human_as_model": conf.get("human_as_model", "false") == "true",
|
|
1961
|
-
"skip_build_index": conf.get("skip_build_index", "true") == "true",
|
|
1962
|
-
"skip_confirm": conf.get("skip_confirm", "true") == "true",
|
|
1963
|
-
"silence": conf.get("silence", "true") == "true",
|
|
1964
|
-
"exclude_files": memory.get("exclude_files", []),
|
|
1965
|
-
}
|
|
1966
|
-
|
|
1967
|
-
current_files = memory["current_files"]["files"] + get_llm_friendly_package_docs(
|
|
1968
|
-
return_paths=True
|
|
1969
|
-
)
|
|
1970
|
-
|
|
1971
|
-
if conf.get("enable_global_memory", "false") in ["true", "True",True]:
|
|
1972
|
-
current_files += get_global_memory_file_paths()
|
|
1973
|
-
|
|
1974
|
-
yaml_config["urls"] = current_files
|
|
1975
|
-
|
|
1976
|
-
if "emb_model" in conf:
|
|
1977
|
-
yaml_config["emb_model"] = conf["emb_model"]
|
|
1978
|
-
|
|
1979
|
-
# 解析命令
|
|
1980
|
-
commands_infos = parse_query(query)
|
|
1981
|
-
if len(commands_infos) > 0:
|
|
1982
|
-
if "query" in commands_infos:
|
|
1983
|
-
query = " ".join(commands_infos["query"]["args"])
|
|
1984
|
-
else:
|
|
1985
|
-
temp_query = ""
|
|
1986
|
-
for (command,command_info) in commands_infos.items():
|
|
1987
|
-
if command_info["args"]:
|
|
1988
|
-
temp_query = " ".join(command_info["args"])
|
|
1989
|
-
query = temp_query
|
|
1990
|
-
|
|
1991
|
-
is_new = "new" in commands_infos
|
|
1992
|
-
|
|
1993
|
-
if "learn" in commands_infos:
|
|
1994
|
-
commands_infos["no_context"] = {}
|
|
1995
|
-
|
|
1996
|
-
if "review" in commands_infos:
|
|
1997
|
-
commands_infos["no_context"] = {}
|
|
1998
|
-
|
|
1999
|
-
yaml_config["action"] = commands_infos
|
|
2000
|
-
|
|
2001
|
-
for key, value in conf.items():
|
|
2002
|
-
converted_value = convert_config_value(key, value)
|
|
2003
|
-
if converted_value is not None:
|
|
2004
|
-
yaml_config[key] = converted_value
|
|
2005
|
-
|
|
2006
|
-
query = Image.convert_image_paths_from(query)
|
|
2007
|
-
|
|
2008
|
-
yaml_config["query"] = query
|
|
2009
|
-
|
|
2010
|
-
yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
|
|
2011
|
-
|
|
2012
|
-
execute_file = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
2013
|
-
|
|
2014
|
-
with open(os.path.join(execute_file), "w",encoding="utf-8") as f:
|
|
2015
|
-
f.write(yaml_content)
|
|
1317
|
+
"""
|
|
1318
|
+
处理聊天命令,使用 ChatHandler 进行统一处理
|
|
2016
1319
|
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
auto_coder_main(cmd)
|
|
1320
|
+
Args:
|
|
1321
|
+
query: 聊天查询字符串
|
|
1322
|
+
"""
|
|
1323
|
+
from autocoder.common.file_handler import ChatHandler
|
|
2022
1324
|
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
finally:
|
|
2026
|
-
os.remove(execute_file)
|
|
1325
|
+
handler = ChatHandler()
|
|
1326
|
+
handler.handle_chat_command(query)
|
|
2027
1327
|
|
|
2028
1328
|
|
|
2029
|
-
@run_in_raw_thread()
|
|
2030
1329
|
def summon(query: str):
|
|
1330
|
+
memory = get_current_memory()
|
|
2031
1331
|
conf = memory.get("conf", {})
|
|
2032
|
-
current_files =
|
|
1332
|
+
current_files = get_current_files()
|
|
2033
1333
|
|
|
2034
1334
|
file_contents = []
|
|
2035
1335
|
for file in current_files:
|
|
2036
1336
|
if os.path.exists(file):
|
|
2037
1337
|
try:
|
|
2038
|
-
with open(file, "r",encoding="utf-8") as f:
|
|
1338
|
+
with open(file, "r", encoding="utf-8") as f:
|
|
2039
1339
|
content = f.read()
|
|
2040
1340
|
s = f"##File: {file}\n{content}\n\n"
|
|
2041
1341
|
file_contents.append(s)
|
|
@@ -2071,7 +1371,7 @@ def summon(query: str):
|
|
|
2071
1371
|
|
|
2072
1372
|
execute_file = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
2073
1373
|
|
|
2074
|
-
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:
|
|
2075
1375
|
f.write(yaml_content)
|
|
2076
1376
|
|
|
2077
1377
|
def execute_summon():
|
|
@@ -2083,9 +1383,8 @@ def summon(query: str):
|
|
|
2083
1383
|
os.remove(execute_file)
|
|
2084
1384
|
|
|
2085
1385
|
|
|
2086
|
-
@run_in_raw_thread()
|
|
2087
1386
|
def design(query: str):
|
|
2088
|
-
|
|
1387
|
+
memory = get_current_memory()
|
|
2089
1388
|
conf = memory.get("conf", {})
|
|
2090
1389
|
yaml_config = {
|
|
2091
1390
|
"include_file": ["./base/base.yml"],
|
|
@@ -2118,7 +1417,7 @@ def design(query: str):
|
|
|
2118
1417
|
|
|
2119
1418
|
execute_file = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
2120
1419
|
|
|
2121
|
-
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:
|
|
2122
1421
|
f.write(yaml_content)
|
|
2123
1422
|
|
|
2124
1423
|
def execute_design():
|
|
@@ -2130,117 +1429,21 @@ def design(query: str):
|
|
|
2130
1429
|
os.remove(execute_file)
|
|
2131
1430
|
|
|
2132
1431
|
|
|
2133
|
-
@run_in_raw_thread()
|
|
2134
1432
|
def active_context(query: str):
|
|
2135
1433
|
"""
|
|
2136
|
-
|
|
2137
|
-
|
|
1434
|
+
处理活动上下文命令,使用 ActiveContextHandler 进行统一处理
|
|
1435
|
+
|
|
2138
1436
|
Args:
|
|
2139
1437
|
query: 命令参数,例如 "list" 列出所有任务
|
|
2140
|
-
"""
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
if len(commands_infos) > 0:
|
|
2146
|
-
if "list" in commands_infos:
|
|
2147
|
-
command = "list"
|
|
2148
|
-
if "run" in commands_infos:
|
|
2149
|
-
command = "run"
|
|
2150
|
-
|
|
2151
|
-
args = get_final_config()
|
|
2152
|
-
printer = Printer()
|
|
2153
|
-
# 获取LLM实例
|
|
2154
|
-
llm = get_single_llm(args.model,product_mode=args.product_mode)
|
|
2155
|
-
action_file_manager = ActionYmlFileManager(args.source_dir)
|
|
2156
|
-
|
|
2157
|
-
# 获取配置和参数
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
active_context_manager = ActiveContextManager(llm, args.source_dir)
|
|
2161
|
-
if command == "run":
|
|
2162
|
-
file_name = commands_infos["run"]["args"][-1]
|
|
2163
|
-
args.file = action_file_manager.get_full_path_by_file_name(file_name)
|
|
2164
|
-
## 因为更新了args.file
|
|
2165
|
-
active_context_manager = ActiveContextManager(llm, args.source_dir)
|
|
2166
|
-
task_id = active_context_manager.process_changes(args)
|
|
2167
|
-
printer.print_in_terminal("active_context_background_task",
|
|
2168
|
-
style="blue",
|
|
2169
|
-
task_id=task_id)
|
|
2170
|
-
|
|
2171
|
-
# 处理不同的命令
|
|
2172
|
-
if command == "list":
|
|
2173
|
-
# 获取所有任务
|
|
2174
|
-
all_tasks = active_context_manager.get_all_tasks()
|
|
2175
|
-
|
|
2176
|
-
if not all_tasks:
|
|
2177
|
-
console = Console()
|
|
2178
|
-
console.print("[yellow]没有找到任何活动上下文任务[/yellow]")
|
|
2179
|
-
return
|
|
2180
|
-
|
|
2181
|
-
# 创建表格
|
|
2182
|
-
table = Table(title="活动上下文任务列表", show_lines=True, expand=True)
|
|
2183
|
-
table.add_column("任务ID", style="cyan", no_wrap=False)
|
|
2184
|
-
table.add_column("状态", style="green", no_wrap=False)
|
|
2185
|
-
table.add_column("开始时间", style="yellow", no_wrap=False)
|
|
2186
|
-
table.add_column("完成时间", style="yellow", no_wrap=False)
|
|
2187
|
-
table.add_column("文件", style="blue", no_wrap=False)
|
|
2188
|
-
table.add_column("Token统计", style="magenta", no_wrap=False)
|
|
2189
|
-
table.add_column("费用", style="red", no_wrap=False)
|
|
2190
|
-
|
|
2191
|
-
# 添加任务数据
|
|
2192
|
-
for task in all_tasks:
|
|
2193
|
-
status = task.get("status", "未知")
|
|
2194
|
-
status_display = status
|
|
2195
|
-
|
|
2196
|
-
# 根据状态设置不同的显示样式
|
|
2197
|
-
if status == "completed":
|
|
2198
|
-
status_display = "[green]已完成[/green]"
|
|
2199
|
-
elif status == "running":
|
|
2200
|
-
status_display = "[blue]运行中[/blue]"
|
|
2201
|
-
elif status == "queued":
|
|
2202
|
-
position = task.get("queue_position", 0)
|
|
2203
|
-
status_display = f"[yellow]排队中 (位置: {position})[/yellow]"
|
|
2204
|
-
elif status == "failed":
|
|
2205
|
-
status_display = "[red]失败[/red]"
|
|
2206
|
-
|
|
2207
|
-
# 格式化时间
|
|
2208
|
-
start_time = task.get("start_time", "")
|
|
2209
|
-
start_time_str = start_time.strftime("%Y-%m-%d %H:%M:%S") if start_time else "未知"
|
|
2210
|
-
|
|
2211
|
-
completion_time = task.get("completion_time", "")
|
|
2212
|
-
completion_time_str = completion_time.strftime("%Y-%m-%d %H:%M:%S") if completion_time else "-"
|
|
2213
|
-
|
|
2214
|
-
# 获取文件名
|
|
2215
|
-
file_name = task.get("file_name", "未知")
|
|
2216
|
-
|
|
2217
|
-
# 获取token信息
|
|
2218
|
-
total_tokens = task.get("total_tokens", 0)
|
|
2219
|
-
input_tokens = task.get("input_tokens", 0)
|
|
2220
|
-
output_tokens = task.get("output_tokens", 0)
|
|
2221
|
-
token_info = f"总计: {total_tokens:,}\n输入: {input_tokens:,}\n输出: {output_tokens:,}"
|
|
2222
|
-
|
|
2223
|
-
# 获取费用信息
|
|
2224
|
-
cost = task.get("cost", 0.0)
|
|
2225
|
-
cost_info = f"${cost:.6f}"
|
|
2226
|
-
|
|
2227
|
-
# 添加到表格
|
|
2228
|
-
table.add_row(
|
|
2229
|
-
task.get("task_id", "未知"),
|
|
2230
|
-
status_display,
|
|
2231
|
-
start_time_str,
|
|
2232
|
-
completion_time_str,
|
|
2233
|
-
file_name,
|
|
2234
|
-
token_info,
|
|
2235
|
-
cost_info
|
|
2236
|
-
)
|
|
2237
|
-
|
|
2238
|
-
# 显示表格
|
|
2239
|
-
console = Console(width=120) # 设置更宽的显示宽度
|
|
2240
|
-
console.print(table)
|
|
1438
|
+
"""
|
|
1439
|
+
from autocoder.common.file_handler import ActiveContextHandler
|
|
1440
|
+
|
|
1441
|
+
handler = ActiveContextHandler()
|
|
1442
|
+
handler.handle_active_context_command(query)
|
|
2241
1443
|
|
|
2242
1444
|
|
|
2243
1445
|
def voice_input():
|
|
1446
|
+
memory = get_current_memory()
|
|
2244
1447
|
conf = memory.get("conf", {})
|
|
2245
1448
|
yaml_config = {
|
|
2246
1449
|
"include_file": ["./base/base.yml"],
|
|
@@ -2257,7 +1460,7 @@ def voice_input():
|
|
|
2257
1460
|
|
|
2258
1461
|
execute_file = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
2259
1462
|
|
|
2260
|
-
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:
|
|
2261
1464
|
f.write(yaml_content)
|
|
2262
1465
|
|
|
2263
1466
|
def execute_voice2text_command():
|
|
@@ -2265,14 +1468,16 @@ def voice_input():
|
|
|
2265
1468
|
|
|
2266
1469
|
try:
|
|
2267
1470
|
execute_voice2text_command()
|
|
2268
|
-
with open(
|
|
1471
|
+
with open(
|
|
1472
|
+
os.path.join(".auto-coder", "exchange.txt"), "r", encoding="utf-8"
|
|
1473
|
+
) as f:
|
|
2269
1474
|
return f.read()
|
|
2270
1475
|
finally:
|
|
2271
1476
|
os.remove(execute_file)
|
|
2272
1477
|
|
|
2273
1478
|
|
|
2274
|
-
@run_in_raw_thread()
|
|
2275
1479
|
def generate_shell_command(input_text):
|
|
1480
|
+
memory = get_current_memory()
|
|
2276
1481
|
conf = memory.get("conf", {})
|
|
2277
1482
|
yaml_config = {
|
|
2278
1483
|
"include_file": ["./base/base.yml"],
|
|
@@ -2283,432 +1488,62 @@ def generate_shell_command(input_text):
|
|
|
2283
1488
|
|
|
2284
1489
|
yaml_config["query"] = input_text
|
|
2285
1490
|
|
|
2286
|
-
yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
|
|
2287
|
-
|
|
2288
|
-
execute_file = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
2289
|
-
|
|
2290
|
-
with open(os.path.join(execute_file), "w",encoding="utf-8") as f:
|
|
2291
|
-
f.write(yaml_content)
|
|
2292
|
-
|
|
2293
|
-
try:
|
|
2294
|
-
auto_coder_main(["agent", "generate_command", "--file", execute_file])
|
|
2295
|
-
with open(os.path.join(".auto-coder", "exchange.txt"), "r",encoding="utf-8") as f:
|
|
2296
|
-
shell_script = f.read()
|
|
2297
|
-
result_manager = ResultManager()
|
|
2298
|
-
result_manager.add_result(content=shell_script,meta={
|
|
2299
|
-
"action": "generate_shell_command",
|
|
2300
|
-
"input": {
|
|
2301
|
-
"query": input_text
|
|
2302
|
-
}
|
|
2303
|
-
})
|
|
2304
|
-
return shell_script
|
|
2305
|
-
finally:
|
|
2306
|
-
os.remove(execute_file)
|
|
2307
|
-
|
|
2308
|
-
def manage_models(query: str):
|
|
2309
|
-
"""
|
|
2310
|
-
Handle /models subcommands:
|
|
2311
|
-
/models /list - List all models (default + custom)
|
|
2312
|
-
/models /add <name> <api_key> - Add model with simplified params
|
|
2313
|
-
/models /add_model name=xxx base_url=xxx ... - Add model with custom params
|
|
2314
|
-
/models /remove <name> - Remove model by name
|
|
2315
|
-
"""
|
|
2316
|
-
console = Console()
|
|
2317
|
-
printer = Printer(console=console)
|
|
2318
|
-
|
|
2319
|
-
product_mode = memory.get("product_mode", "lite")
|
|
2320
|
-
if product_mode != "lite":
|
|
2321
|
-
printer.print_in_terminal("models_lite_only", style="red")
|
|
2322
|
-
return
|
|
2323
|
-
|
|
2324
|
-
models_data = models_module.load_models()
|
|
2325
|
-
subcmd = ""
|
|
2326
|
-
if "/list" in query:
|
|
2327
|
-
subcmd = "/list"
|
|
2328
|
-
query = query.replace("/list", "", 1).strip()
|
|
2329
|
-
|
|
2330
|
-
if "/add_model" in query:
|
|
2331
|
-
subcmd = "/add_model"
|
|
2332
|
-
query = query.replace("/add_model", "", 1).strip()
|
|
2333
|
-
|
|
2334
|
-
if "/add" in query:
|
|
2335
|
-
subcmd = "/add"
|
|
2336
|
-
query = query.replace("/add", "", 1).strip()
|
|
2337
|
-
|
|
2338
|
-
# alias to /add
|
|
2339
|
-
if "/activate" in query:
|
|
2340
|
-
subcmd = "/add"
|
|
2341
|
-
query = query.replace("/activate", "", 1).strip()
|
|
2342
|
-
|
|
2343
|
-
if "/remove" in query:
|
|
2344
|
-
subcmd = "/remove"
|
|
2345
|
-
query = query.replace("/remove", "", 1).strip()
|
|
2346
|
-
|
|
2347
|
-
if "/speed-test" in query:
|
|
2348
|
-
subcmd = "/speed-test"
|
|
2349
|
-
query = query.replace("/speed-test", "", 1).strip()
|
|
2350
|
-
|
|
2351
|
-
if "/speed_test" in query:
|
|
2352
|
-
subcmd = "/speed-test"
|
|
2353
|
-
query = query.replace("/speed_test", "", 1).strip()
|
|
2354
|
-
|
|
2355
|
-
if "input_price" in query:
|
|
2356
|
-
subcmd = "/input_price"
|
|
2357
|
-
query = query.replace("/input_price", "", 1).strip()
|
|
2358
|
-
|
|
2359
|
-
if "output_price" in query:
|
|
2360
|
-
subcmd = "/output_price"
|
|
2361
|
-
query = query.replace("/output_price", "", 1).strip()
|
|
2362
|
-
|
|
2363
|
-
if "/speed" in query:
|
|
2364
|
-
subcmd = "/speed"
|
|
2365
|
-
query = query.replace("/speed", "", 1).strip()
|
|
1491
|
+
yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
|
|
2366
1492
|
|
|
1493
|
+
execute_file = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
2367
1494
|
|
|
1495
|
+
with open(os.path.join(execute_file), "w", encoding="utf-8") as f:
|
|
1496
|
+
f.write(yaml_content)
|
|
2368
1497
|
|
|
2369
|
-
|
|
2370
|
-
|
|
1498
|
+
try:
|
|
1499
|
+
auto_coder_main(["agent", "generate_command", "--file", execute_file])
|
|
1500
|
+
with open(
|
|
1501
|
+
os.path.join(".auto-coder", "exchange.txt"), "r", encoding="utf-8"
|
|
1502
|
+
) as f:
|
|
1503
|
+
shell_script = f.read()
|
|
1504
|
+
result_manager = ResultManager()
|
|
1505
|
+
result_manager.add_result(
|
|
1506
|
+
content=shell_script,
|
|
1507
|
+
meta={"action": "generate_shell_command", "input": {"query": input_text}},
|
|
1508
|
+
)
|
|
1509
|
+
return shell_script
|
|
1510
|
+
finally:
|
|
1511
|
+
os.remove(execute_file)
|
|
2371
1512
|
|
|
2372
|
-
result_manager = ResultManager()
|
|
2373
|
-
if subcmd == "/list":
|
|
2374
|
-
if models_data:
|
|
2375
|
-
# Sort models by speed (average_speed)
|
|
2376
|
-
sorted_models = sorted(models_data, key=lambda x: float(x.get('average_speed', 0)))
|
|
2377
|
-
sorted_models.reverse()
|
|
2378
|
-
|
|
2379
|
-
table = Table(
|
|
2380
|
-
title=printer.get_message_from_key("models_title"),
|
|
2381
|
-
expand=True,
|
|
2382
|
-
show_lines=True
|
|
2383
|
-
)
|
|
2384
|
-
table.add_column("Name", style="cyan", width=30, overflow="fold", no_wrap=False)
|
|
2385
|
-
table.add_column("Model Name", style="magenta", width=30, overflow="fold", no_wrap=False)
|
|
2386
|
-
table.add_column("Base URL", style="white", width=40, overflow="fold", no_wrap=False)
|
|
2387
|
-
table.add_column("Input Price (M)", style="magenta", width=15, overflow="fold", no_wrap=False)
|
|
2388
|
-
table.add_column("Output Price (M)", style="magenta", width=15, overflow="fold", no_wrap=False)
|
|
2389
|
-
table.add_column("Speed (s/req)", style="blue", width=15, overflow="fold", no_wrap=False)
|
|
2390
|
-
for m in sorted_models:
|
|
2391
|
-
# Check if api_key_path exists and file exists
|
|
2392
|
-
is_api_key_set = "api_key" in m
|
|
2393
|
-
name = m.get("name", "")
|
|
2394
|
-
if is_api_key_set:
|
|
2395
|
-
api_key = m.get("api_key", "").strip()
|
|
2396
|
-
if not api_key:
|
|
2397
|
-
printer.print_in_terminal("models_api_key_empty", style="yellow", name=name)
|
|
2398
|
-
name = f"{name} *"
|
|
2399
|
-
|
|
2400
|
-
table.add_row(
|
|
2401
|
-
name,
|
|
2402
|
-
m.get("model_name", ""),
|
|
2403
|
-
m.get("base_url", ""),
|
|
2404
|
-
f"{m.get('input_price', 0.0):.2f}",
|
|
2405
|
-
f"{m.get('output_price', 0.0):.2f}",
|
|
2406
|
-
f"{m.get('average_speed', 0.0):.3f}"
|
|
2407
|
-
)
|
|
2408
|
-
console.print(table)
|
|
2409
|
-
result_manager.add_result(content=json.dumps(sorted_models,ensure_ascii=False),meta={
|
|
2410
|
-
"action": "models",
|
|
2411
|
-
"input": {
|
|
2412
|
-
"query": query
|
|
2413
|
-
}
|
|
2414
|
-
})
|
|
2415
1513
|
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
"action": "models",
|
|
2420
|
-
"input": {
|
|
2421
|
-
"query": query
|
|
2422
|
-
}
|
|
2423
|
-
})
|
|
2424
|
-
|
|
2425
|
-
elif subcmd == "/input_price":
|
|
2426
|
-
args = query.strip().split()
|
|
2427
|
-
if len(args) >= 2:
|
|
2428
|
-
name = args[0]
|
|
2429
|
-
try:
|
|
2430
|
-
price = float(args[1])
|
|
2431
|
-
if models_module.update_model_input_price(name, price):
|
|
2432
|
-
printer.print_in_terminal("models_input_price_updated", style="green", name=name, price=price)
|
|
2433
|
-
result_manager.add_result(content=f"models_input_price_updated: {name} {price}",meta={
|
|
2434
|
-
"action": "models",
|
|
2435
|
-
"input": {
|
|
2436
|
-
"query": query
|
|
2437
|
-
}
|
|
2438
|
-
})
|
|
2439
|
-
else:
|
|
2440
|
-
printer.print_in_terminal("models_not_found", style="red", name=name)
|
|
2441
|
-
result_manager.add_result(content=f"models_not_found: {name}",meta={
|
|
2442
|
-
"action": "models",
|
|
2443
|
-
"input": {
|
|
2444
|
-
"query": query
|
|
2445
|
-
}
|
|
2446
|
-
})
|
|
2447
|
-
except ValueError as e:
|
|
2448
|
-
result_manager.add_result(content=f"models_invalid_price: {str(e)}",meta={
|
|
2449
|
-
"action": "models",
|
|
2450
|
-
"input": {
|
|
2451
|
-
"query": query
|
|
2452
|
-
}
|
|
2453
|
-
})
|
|
2454
|
-
printer.print_in_terminal("models_invalid_price", style="red", error=str(e))
|
|
2455
|
-
else:
|
|
2456
|
-
result_manager.add_result(content=printer.get_message_from_key("models_input_price_usage"),meta={
|
|
2457
|
-
"action": "models",
|
|
2458
|
-
"input": {
|
|
2459
|
-
"query": query
|
|
2460
|
-
}
|
|
2461
|
-
})
|
|
2462
|
-
printer.print_in_terminal("models_input_price_usage", style="red")
|
|
2463
|
-
|
|
2464
|
-
elif subcmd == "/output_price":
|
|
2465
|
-
args = query.strip().split()
|
|
2466
|
-
if len(args) >= 2:
|
|
2467
|
-
name = args[0]
|
|
2468
|
-
try:
|
|
2469
|
-
price = float(args[1])
|
|
2470
|
-
if models_module.update_model_output_price(name, price):
|
|
2471
|
-
printer.print_in_terminal("models_output_price_updated", style="green", name=name, price=price)
|
|
2472
|
-
result_manager.add_result(content=f"models_output_price_updated: {name} {price}",meta={
|
|
2473
|
-
"action": "models",
|
|
2474
|
-
"input": {
|
|
2475
|
-
"query": query
|
|
2476
|
-
}
|
|
2477
|
-
})
|
|
2478
|
-
else:
|
|
2479
|
-
printer.print_in_terminal("models_not_found", style="red", name=name)
|
|
2480
|
-
result_manager.add_result(content=f"models_not_found: {name}",meta={
|
|
2481
|
-
"action": "models",
|
|
2482
|
-
"input": {
|
|
2483
|
-
"query": query
|
|
2484
|
-
}
|
|
2485
|
-
})
|
|
2486
|
-
except ValueError as e:
|
|
2487
|
-
printer.print_in_terminal("models_invalid_price", style="red", error=str(e))
|
|
2488
|
-
result_manager.add_result(content=f"models_invalid_price: {str(e)}",meta={
|
|
2489
|
-
"action": "models",
|
|
2490
|
-
"input": {
|
|
2491
|
-
"query": query
|
|
2492
|
-
}
|
|
2493
|
-
})
|
|
2494
|
-
else:
|
|
2495
|
-
result_manager.add_result(content=printer.get_message_from_key("models_output_price_usage"),meta={
|
|
2496
|
-
"action": "models",
|
|
2497
|
-
"input": {
|
|
2498
|
-
"query": query
|
|
2499
|
-
}
|
|
2500
|
-
})
|
|
2501
|
-
printer.print_in_terminal("models_output_price_usage", style="red")
|
|
2502
|
-
|
|
2503
|
-
elif subcmd == "/speed":
|
|
2504
|
-
args = query.strip().split()
|
|
2505
|
-
if len(args) >= 2:
|
|
2506
|
-
name = args[0]
|
|
2507
|
-
try:
|
|
2508
|
-
speed = float(args[1])
|
|
2509
|
-
if models_module.update_model_speed(name, speed):
|
|
2510
|
-
printer.print_in_terminal("models_speed_updated", style="green", name=name, speed=speed)
|
|
2511
|
-
result_manager.add_result(content=f"models_speed_updated: {name} {speed}",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
|
-
printer.print_in_terminal("models_invalid_speed", style="red", error=str(e))
|
|
2527
|
-
result_manager.add_result(content=f"models_invalid_speed: {str(e)}",meta={
|
|
2528
|
-
"action": "models",
|
|
2529
|
-
"input": {
|
|
2530
|
-
"query": query
|
|
2531
|
-
}
|
|
2532
|
-
})
|
|
2533
|
-
else:
|
|
2534
|
-
result_manager.add_result(content=printer.get_message_from_key("models_speed_usage"),meta={
|
|
2535
|
-
"action": "models",
|
|
2536
|
-
"input": {
|
|
2537
|
-
"query": query
|
|
2538
|
-
}
|
|
2539
|
-
})
|
|
2540
|
-
printer.print_in_terminal("models_speed_usage", style="red")
|
|
2541
|
-
|
|
2542
|
-
elif subcmd == "/speed-test":
|
|
2543
|
-
from autocoder.common.model_speed_tester import render_speed_test_in_terminal
|
|
2544
|
-
test_rounds = 1 # 默认测试轮数
|
|
2545
|
-
|
|
2546
|
-
enable_long_context = False
|
|
2547
|
-
if "/long_context" in query:
|
|
2548
|
-
enable_long_context = True
|
|
2549
|
-
query = query.replace("/long_context", "", 1).strip()
|
|
2550
|
-
|
|
2551
|
-
if "/long-context" in query:
|
|
2552
|
-
enable_long_context = True
|
|
2553
|
-
query = query.replace("/long-context", "", 1).strip()
|
|
2554
|
-
|
|
2555
|
-
# 解析可选的测试轮数参数
|
|
2556
|
-
args = query.strip().split()
|
|
2557
|
-
if args and args[0].isdigit():
|
|
2558
|
-
test_rounds = int(args[0])
|
|
2559
|
-
|
|
2560
|
-
render_speed_test_in_terminal(product_mode, test_rounds,enable_long_context=enable_long_context)
|
|
2561
|
-
## 等待优化,获取明细数据
|
|
2562
|
-
result_manager.add_result(content="models test success",meta={
|
|
2563
|
-
"action": "models",
|
|
2564
|
-
"input": {
|
|
2565
|
-
"query": query
|
|
2566
|
-
}
|
|
2567
|
-
})
|
|
2568
|
-
|
|
2569
|
-
elif subcmd == "/add":
|
|
2570
|
-
# Support both simplified and legacy formats
|
|
2571
|
-
args = query.strip().split(" ")
|
|
2572
|
-
if len(args) == 2:
|
|
2573
|
-
# Simplified: /models /add <name> <api_key>
|
|
2574
|
-
name, api_key = args[0], args[1]
|
|
2575
|
-
result = models_module.update_model_with_api_key(name, api_key)
|
|
2576
|
-
if result:
|
|
2577
|
-
result_manager.add_result(content=f"models_added: {name}",meta={
|
|
2578
|
-
"action": "models",
|
|
2579
|
-
"input": {
|
|
2580
|
-
"query": query
|
|
2581
|
-
}
|
|
2582
|
-
})
|
|
2583
|
-
printer.print_in_terminal("models_added", style="green", name=name)
|
|
2584
|
-
else:
|
|
2585
|
-
result_manager.add_result(content=f"models_add_failed: {name}",meta={
|
|
2586
|
-
"action": "models",
|
|
2587
|
-
"input": {
|
|
2588
|
-
"query": query
|
|
2589
|
-
}
|
|
2590
|
-
})
|
|
2591
|
-
printer.print_in_terminal("models_add_failed", style="red", name=name)
|
|
2592
|
-
else:
|
|
2593
|
-
models_list = "\n".join([m["name"] for m in models_module.default_models_list])
|
|
2594
|
-
printer.print_in_terminal("models_add_usage", style="red", models=models_list)
|
|
2595
|
-
result_manager.add_result(content=printer.get_message_from_key_with_format("models_add_usage",models=models_list),meta={
|
|
2596
|
-
"action": "models",
|
|
2597
|
-
"input": {
|
|
2598
|
-
"query": query
|
|
2599
|
-
}
|
|
2600
|
-
})
|
|
2601
|
-
|
|
2602
|
-
elif subcmd == "/add_model":
|
|
2603
|
-
# Parse key=value pairs: /models /add_model name=abc base_url=http://xx ...
|
|
2604
|
-
# Collect key=value pairs
|
|
2605
|
-
kv_pairs = shlex.split(query)
|
|
2606
|
-
data_dict = {}
|
|
2607
|
-
for pair in kv_pairs:
|
|
2608
|
-
if '=' not in pair:
|
|
2609
|
-
printer.print_in_terminal("models_add_model_params", style="red")
|
|
2610
|
-
continue
|
|
2611
|
-
k, v = pair.split('=', 1)
|
|
2612
|
-
data_dict[k.strip()] = v.strip()
|
|
2613
|
-
|
|
2614
|
-
# Name is required
|
|
2615
|
-
if "name" not in data_dict:
|
|
2616
|
-
printer.print_in_terminal("models_add_model_name_required", style="red")
|
|
2617
|
-
return
|
|
1514
|
+
def manage_models(query: str):
|
|
1515
|
+
"""
|
|
1516
|
+
处理模型管理命令,使用 ModelsHandler 进行统一处理
|
|
2618
1517
|
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
"action": "models",
|
|
2624
|
-
"input": {
|
|
2625
|
-
"query": query
|
|
2626
|
-
}
|
|
2627
|
-
})
|
|
2628
|
-
return
|
|
1518
|
+
Args:
|
|
1519
|
+
query: 查询字符串,支持多种模型管理子命令
|
|
1520
|
+
"""
|
|
1521
|
+
from autocoder.common.file_handler import ModelsHandler
|
|
2629
1522
|
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
"name": data_dict["name"],
|
|
2633
|
-
"model_type": data_dict.get("model_type", "saas/openai"),
|
|
2634
|
-
"model_name": data_dict.get("model_name", data_dict["name"]),
|
|
2635
|
-
"base_url": data_dict.get("base_url", "https://api.openai.com/v1"),
|
|
2636
|
-
"api_key_path": data_dict.get("api_key_path", "api.openai.com"),
|
|
2637
|
-
"description": data_dict.get("description", ""),
|
|
2638
|
-
"is_reasoning": data_dict.get("is_reasoning", "false") in ["true", "True", "TRUE", "1"]
|
|
2639
|
-
}
|
|
1523
|
+
handler = ModelsHandler()
|
|
1524
|
+
handler.handle_models_command(query)
|
|
2640
1525
|
|
|
2641
|
-
models_data.append(final_model)
|
|
2642
|
-
models_module.save_models(models_data)
|
|
2643
|
-
printer.print_in_terminal("models_add_model_success", style="green", name=data_dict["name"])
|
|
2644
|
-
result_manager.add_result(content=f"models_add_model_success: {data_dict['name']}",meta={
|
|
2645
|
-
"action": "models",
|
|
2646
|
-
"input": {
|
|
2647
|
-
"query": query
|
|
2648
|
-
}
|
|
2649
|
-
})
|
|
2650
|
-
|
|
2651
|
-
elif subcmd == "/remove":
|
|
2652
|
-
args = query.strip().split(" ")
|
|
2653
|
-
if len(args) < 1:
|
|
2654
|
-
printer.print_in_terminal("models_add_usage", style="red")
|
|
2655
|
-
result_manager.add_result(content=printer.get_message_from_key("models_add_usage"),meta={
|
|
2656
|
-
"action": "models",
|
|
2657
|
-
"input": {
|
|
2658
|
-
"query": query
|
|
2659
|
-
}
|
|
2660
|
-
})
|
|
2661
|
-
return
|
|
2662
|
-
name = args[0]
|
|
2663
|
-
filtered_models = [m for m in models_data if m["name"] != name]
|
|
2664
|
-
if len(filtered_models) == len(models_data):
|
|
2665
|
-
printer.print_in_terminal("models_add_model_remove", style="yellow", name=name)
|
|
2666
|
-
result_manager.add_result(content=printer.get_message_from_key_with_format("models_add_model_remove",name=name),meta={
|
|
2667
|
-
"action": "models",
|
|
2668
|
-
"input": {
|
|
2669
|
-
"query": query
|
|
2670
|
-
}
|
|
2671
|
-
})
|
|
2672
|
-
return
|
|
2673
|
-
models_module.save_models(filtered_models)
|
|
2674
|
-
printer.print_in_terminal("models_add_model_removed", style="green", name=name)
|
|
2675
|
-
result_manager.add_result(content=printer.get_message_from_key_with_format("models_add_model_removed",name=name),meta={
|
|
2676
|
-
"action": "models",
|
|
2677
|
-
"input": {
|
|
2678
|
-
"query": query
|
|
2679
|
-
}
|
|
2680
|
-
})
|
|
2681
|
-
else:
|
|
2682
|
-
printer.print_in_terminal("models_unknown_subcmd", style="yellow", subcmd=subcmd)
|
|
2683
|
-
result_manager.add_result(content=printer.get_message_from_key_with_format("models_unknown_subcmd",subcmd=subcmd),meta={
|
|
2684
|
-
"action": "models",
|
|
2685
|
-
"input": {
|
|
2686
|
-
"query": query
|
|
2687
|
-
}
|
|
2688
|
-
})
|
|
2689
1526
|
|
|
2690
1527
|
def exclude_dirs(dir_names: List[str]):
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
if "exclude_dirs" not in memory:
|
|
2698
|
-
memory["exclude_dirs"] = existing_dirs
|
|
2699
|
-
print(f"Added exclude dirs: {dirs_to_add}")
|
|
2700
|
-
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]))
|
|
2701
1534
|
else:
|
|
2702
1535
|
print("All specified dirs are already in the exclude list.")
|
|
2703
|
-
save_memory()
|
|
2704
1536
|
completer.refresh_files()
|
|
2705
1537
|
|
|
1538
|
+
|
|
2706
1539
|
def exclude_files(query: str):
|
|
1540
|
+
memory_manager = get_memory_manager()
|
|
2707
1541
|
result_manager = ResultManager()
|
|
2708
1542
|
printer = Printer()
|
|
1543
|
+
|
|
2709
1544
|
if "/list" in query:
|
|
2710
1545
|
query = query.replace("/list", "", 1).strip()
|
|
2711
|
-
existing_file_patterns =
|
|
1546
|
+
existing_file_patterns = memory_manager.get_exclude_files()
|
|
2712
1547
|
console = Console()
|
|
2713
1548
|
# 打印表格
|
|
2714
1549
|
table = Table(title="Exclude Files")
|
|
@@ -2716,70 +1551,58 @@ def exclude_files(query: str):
|
|
|
2716
1551
|
for file_pattern in existing_file_patterns:
|
|
2717
1552
|
table.add_row(file_pattern)
|
|
2718
1553
|
console.print(table)
|
|
2719
|
-
result_manager.add_result(
|
|
2720
|
-
"
|
|
2721
|
-
"input": {
|
|
2722
|
-
|
|
2723
|
-
}
|
|
2724
|
-
})
|
|
1554
|
+
result_manager.add_result(
|
|
1555
|
+
content=f"Exclude files: {existing_file_patterns}",
|
|
1556
|
+
meta={"action": "exclude_files", "input": {"query": query}},
|
|
1557
|
+
)
|
|
2725
1558
|
return
|
|
2726
1559
|
|
|
2727
1560
|
if "/drop" in query:
|
|
2728
1561
|
query = query.replace("/drop", "", 1).strip()
|
|
2729
|
-
|
|
2730
|
-
existing_file_patterns.remove(query.strip())
|
|
2731
|
-
memory["exclude_files"] = existing_file_patterns
|
|
2732
|
-
save_memory()
|
|
1562
|
+
removed_patterns = memory_manager.remove_exclude_files([query.strip()])
|
|
2733
1563
|
completer.refresh_files()
|
|
2734
|
-
result_manager.add_result(
|
|
2735
|
-
"
|
|
2736
|
-
"input": {
|
|
2737
|
-
|
|
2738
|
-
}
|
|
2739
|
-
})
|
|
1564
|
+
result_manager.add_result(
|
|
1565
|
+
content=f"Dropped exclude files: {removed_patterns}",
|
|
1566
|
+
meta={"action": "exclude_files", "input": {"query": query}},
|
|
1567
|
+
)
|
|
2740
1568
|
return
|
|
2741
|
-
|
|
1569
|
+
|
|
2742
1570
|
new_file_patterns = query.strip().split(",")
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
"input": {
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
"
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
})
|
|
2768
|
-
save_memory()
|
|
2769
|
-
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}")
|
|
2770
1596
|
else:
|
|
2771
|
-
result_manager.add_result(
|
|
2772
|
-
"
|
|
2773
|
-
"input": {
|
|
2774
|
-
|
|
2775
|
-
}
|
|
2776
|
-
})
|
|
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
|
+
)
|
|
2777
1601
|
print("All specified files are already in the exclude list.")
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
1602
|
|
|
2781
|
-
|
|
1603
|
+
|
|
2782
1604
|
def index_build():
|
|
1605
|
+
memory = get_memory()
|
|
2783
1606
|
conf = memory.get("conf", {})
|
|
2784
1607
|
yaml_config = {
|
|
2785
1608
|
"include_file": ["./base/base.yml"],
|
|
@@ -2794,17 +1617,18 @@ def index_build():
|
|
|
2794
1617
|
yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
|
|
2795
1618
|
yaml_file = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
2796
1619
|
|
|
2797
|
-
with open(yaml_file, "w",encoding="utf-8") as f:
|
|
1620
|
+
with open(yaml_file, "w", encoding="utf-8") as f:
|
|
2798
1621
|
f.write(yaml_content)
|
|
2799
|
-
try:
|
|
2800
|
-
auto_coder_main(["index", "--file", yaml_file])
|
|
1622
|
+
try:
|
|
1623
|
+
auto_coder_main(["index", "--file", yaml_file])
|
|
2801
1624
|
completer.refresh_files()
|
|
2802
1625
|
finally:
|
|
2803
1626
|
os.remove(yaml_file)
|
|
2804
1627
|
|
|
2805
1628
|
|
|
2806
|
-
def get_final_config()->AutoCoderArgs:
|
|
2807
|
-
|
|
1629
|
+
def get_final_config() -> AutoCoderArgs:
|
|
1630
|
+
memory_manager = get_memory_manager()
|
|
1631
|
+
conf = memory_manager.get_all_config()
|
|
2808
1632
|
yaml_config = {
|
|
2809
1633
|
"include_file": ["./base/base.yml"],
|
|
2810
1634
|
"auto_merge": conf.get("auto_merge", "editblock"),
|
|
@@ -2812,9 +1636,9 @@ def get_final_config()->AutoCoderArgs:
|
|
|
2812
1636
|
"skip_build_index": conf.get("skip_build_index", "true") == "true",
|
|
2813
1637
|
"skip_confirm": conf.get("skip_confirm", "true") == "true",
|
|
2814
1638
|
"silence": conf.get("silence", "true") == "true",
|
|
2815
|
-
"include_project_structure": conf.get("include_project_structure", "
|
|
1639
|
+
"include_project_structure": conf.get("include_project_structure", "false")
|
|
2816
1640
|
== "true",
|
|
2817
|
-
"exclude_files":
|
|
1641
|
+
"exclude_files": memory_manager.get_exclude_files(),
|
|
2818
1642
|
}
|
|
2819
1643
|
for key, value in conf.items():
|
|
2820
1644
|
converted_value = convert_config_value(key, value)
|
|
@@ -2823,7 +1647,7 @@ def get_final_config()->AutoCoderArgs:
|
|
|
2823
1647
|
|
|
2824
1648
|
temp_yaml = os.path.join("actions", f"{uuid.uuid4()}.yml")
|
|
2825
1649
|
try:
|
|
2826
|
-
with open(temp_yaml, "w",encoding="utf-8") as f:
|
|
1650
|
+
with open(temp_yaml, "w", encoding="utf-8") as f:
|
|
2827
1651
|
f.write(convert_yaml_config_to_str(yaml_config=yaml_config))
|
|
2828
1652
|
args = convert_yaml_to_config(temp_yaml)
|
|
2829
1653
|
finally:
|
|
@@ -2831,18 +1655,31 @@ def get_final_config()->AutoCoderArgs:
|
|
|
2831
1655
|
os.remove(temp_yaml)
|
|
2832
1656
|
return args
|
|
2833
1657
|
|
|
1658
|
+
|
|
2834
1659
|
def help(query: str):
|
|
2835
|
-
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()
|
|
2836
1668
|
args = get_final_config()
|
|
2837
|
-
product_mode =
|
|
1669
|
+
product_mode = memory_manager.get_config("product_mode", "lite")
|
|
2838
1670
|
llm = get_single_llm(args.chat_model or args.model, product_mode=product_mode)
|
|
2839
|
-
auto_config_tuner = ConfigAutoTuner(
|
|
2840
|
-
|
|
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
|
+
|
|
2841
1678
|
|
|
2842
|
-
@run_in_raw_thread()
|
|
2843
1679
|
def index_export(path: str):
|
|
2844
1680
|
from autocoder.common.index_import_export import export_index
|
|
2845
1681
|
from autocoder.common.printer import Printer
|
|
1682
|
+
|
|
2846
1683
|
printer = Printer()
|
|
2847
1684
|
project_root = os.getcwd()
|
|
2848
1685
|
if export_index(project_root, path):
|
|
@@ -2850,10 +1687,11 @@ def index_export(path: str):
|
|
|
2850
1687
|
else:
|
|
2851
1688
|
printer.print_in_terminal("index_export_fail", path=path)
|
|
2852
1689
|
|
|
2853
|
-
|
|
1690
|
+
|
|
2854
1691
|
def index_import(path: str):
|
|
2855
1692
|
from autocoder.common.index_import_export import import_index
|
|
2856
1693
|
from autocoder.common.printer import Printer
|
|
1694
|
+
|
|
2857
1695
|
printer = Printer()
|
|
2858
1696
|
project_root = os.getcwd()
|
|
2859
1697
|
if import_index(project_root, path):
|
|
@@ -2861,7 +1699,7 @@ def index_import(path: str):
|
|
|
2861
1699
|
else:
|
|
2862
1700
|
printer.print_in_terminal("index_import_fail", path=path)
|
|
2863
1701
|
|
|
2864
|
-
|
|
1702
|
+
|
|
2865
1703
|
def index_query(query: str):
|
|
2866
1704
|
from autocoder.index.entry import build_index_and_filter_files
|
|
2867
1705
|
from autocoder.pyproject import PyProject
|
|
@@ -2871,7 +1709,9 @@ def index_query(query: str):
|
|
|
2871
1709
|
config = get_final_config()
|
|
2872
1710
|
config.query = query
|
|
2873
1711
|
config.skip_filter_index = False
|
|
2874
|
-
llm = get_single_llm(
|
|
1712
|
+
llm = get_single_llm(
|
|
1713
|
+
config.chat_model or config.model, product_mode=config.product_mode
|
|
1714
|
+
)
|
|
2875
1715
|
|
|
2876
1716
|
if config.project_type == "ts":
|
|
2877
1717
|
pp = TSProject(args=config, llm=llm)
|
|
@@ -2880,264 +1720,79 @@ def index_query(query: str):
|
|
|
2880
1720
|
else:
|
|
2881
1721
|
pp = SuffixProject(args=config, llm=llm, file_filter=None)
|
|
2882
1722
|
pp.run()
|
|
2883
|
-
sources = pp.sources
|
|
2884
|
-
source_code_list = build_index_and_filter_files(
|
|
2885
|
-
|
|
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
|
+
|
|
2886
1729
|
|
|
2887
1730
|
def list_files():
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
1731
|
+
"""
|
|
1732
|
+
处理文件列表命令,使用 ListFilesHandler 进行统一处理
|
|
1733
|
+
"""
|
|
1734
|
+
from autocoder.common.file_handler import ListFilesHandler
|
|
2891
1735
|
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
title="Current Files", show_header=True, header_style="bold magenta"
|
|
2895
|
-
)
|
|
2896
|
-
table.add_column("File", style="green")
|
|
2897
|
-
for file in current_files:
|
|
2898
|
-
table.add_row(os.path.relpath(file, project_root))
|
|
2899
|
-
console.print(Panel(table, border_style="blue"))
|
|
2900
|
-
else:
|
|
2901
|
-
console.print(
|
|
2902
|
-
Panel(
|
|
2903
|
-
"No files in the current session.",
|
|
2904
|
-
title="Current Files",
|
|
2905
|
-
border_style="yellow",
|
|
2906
|
-
)
|
|
2907
|
-
)
|
|
1736
|
+
handler = ListFilesHandler()
|
|
1737
|
+
handler.handle_list_files_command()
|
|
2908
1738
|
|
|
2909
1739
|
|
|
2910
1740
|
def gen_and_exec_shell_command(query: str):
|
|
2911
|
-
from rich.prompt import Confirm
|
|
2912
|
-
from autocoder.common.printer import Printer
|
|
2913
|
-
from rich.console import Console
|
|
2914
|
-
|
|
2915
1741
|
printer = Printer()
|
|
2916
1742
|
console = Console()
|
|
2917
1743
|
# Generate the shell script
|
|
2918
|
-
shell_script = generate_shell_command(query)
|
|
1744
|
+
shell_script = generate_shell_command(query)
|
|
2919
1745
|
|
|
2920
1746
|
# Ask for confirmation using rich
|
|
2921
1747
|
if Confirm.ask(
|
|
2922
|
-
printer.get_message_from_key("confirm_execute_shell_script"),
|
|
2923
|
-
default=False
|
|
1748
|
+
printer.get_message_from_key("confirm_execute_shell_script"), default=False
|
|
2924
1749
|
):
|
|
2925
1750
|
execute_shell_command(shell_script)
|
|
2926
1751
|
else:
|
|
2927
1752
|
console.print(
|
|
2928
1753
|
Panel(
|
|
2929
1754
|
printer.get_message_from_key("shell_script_not_executed"),
|
|
2930
|
-
border_style="yellow"
|
|
1755
|
+
border_style="yellow",
|
|
2931
1756
|
)
|
|
2932
1757
|
)
|
|
2933
1758
|
|
|
2934
1759
|
|
|
2935
1760
|
def lib_command(args: List[str]):
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
llm_friendly_packages_dir = os.path.join(lib_dir, "llm_friendly_packages")
|
|
2939
|
-
|
|
2940
|
-
if not os.path.exists(lib_dir):
|
|
2941
|
-
os.makedirs(lib_dir)
|
|
2942
|
-
|
|
2943
|
-
if "libs" not in memory:
|
|
2944
|
-
memory["libs"] = {}
|
|
2945
|
-
|
|
2946
|
-
if not args:
|
|
2947
|
-
console.print(
|
|
2948
|
-
"Please specify a subcommand: /add, /remove, /list, /list_all, /set-proxy, /refresh, or /get"
|
|
2949
|
-
)
|
|
2950
|
-
return
|
|
2951
|
-
|
|
2952
|
-
subcommand = args[0]
|
|
2953
|
-
|
|
2954
|
-
if subcommand == "/add":
|
|
2955
|
-
if len(args) < 2:
|
|
2956
|
-
console.print("Please specify a library name to add")
|
|
2957
|
-
return
|
|
2958
|
-
lib_name = args[1].strip()
|
|
2959
|
-
|
|
2960
|
-
# Clone the repository if it doesn't exist
|
|
2961
|
-
if not os.path.exists(llm_friendly_packages_dir):
|
|
2962
|
-
console.print("Cloning llm_friendly_packages repository...")
|
|
2963
|
-
try:
|
|
2964
|
-
proxy_url = memory.get(
|
|
2965
|
-
"lib-proxy", "https://github.com/allwefantasy/llm_friendly_packages"
|
|
2966
|
-
)
|
|
2967
|
-
git.Repo.clone_from(
|
|
2968
|
-
proxy_url,
|
|
2969
|
-
llm_friendly_packages_dir,
|
|
2970
|
-
)
|
|
2971
|
-
console.print(
|
|
2972
|
-
"Successfully cloned llm_friendly_packages repository")
|
|
2973
|
-
except git.exc.GitCommandError as e:
|
|
2974
|
-
console.print(f"Error cloning repository: {e}")
|
|
2975
|
-
|
|
2976
|
-
if lib_name in memory["libs"]:
|
|
2977
|
-
console.print(f"Library {lib_name} is already added")
|
|
2978
|
-
else:
|
|
2979
|
-
memory["libs"][lib_name] = {}
|
|
2980
|
-
console.print(f"Added library: {lib_name}")
|
|
2981
|
-
|
|
2982
|
-
save_memory()
|
|
2983
|
-
|
|
2984
|
-
elif subcommand == "/remove":
|
|
2985
|
-
if len(args) < 2:
|
|
2986
|
-
console.print("Please specify a library name to remove")
|
|
2987
|
-
return
|
|
2988
|
-
lib_name = args[1].strip()
|
|
2989
|
-
if lib_name in memory["libs"]:
|
|
2990
|
-
del memory["libs"][lib_name]
|
|
2991
|
-
console.print(f"Removed library: {lib_name}")
|
|
2992
|
-
save_memory()
|
|
2993
|
-
else:
|
|
2994
|
-
console.print(f"Library {lib_name} is not in the list")
|
|
2995
|
-
|
|
2996
|
-
elif subcommand == "/list":
|
|
2997
|
-
if memory["libs"]:
|
|
2998
|
-
table = Table(title="Added Libraries")
|
|
2999
|
-
table.add_column("Library Name", style="cyan")
|
|
3000
|
-
for lib_name in memory["libs"]:
|
|
3001
|
-
table.add_row(lib_name)
|
|
3002
|
-
console.print(table)
|
|
3003
|
-
else:
|
|
3004
|
-
console.print("No libraries added yet")
|
|
3005
|
-
|
|
3006
|
-
elif subcommand == "/list_all":
|
|
3007
|
-
if not os.path.exists(llm_friendly_packages_dir):
|
|
3008
|
-
console.print("llm_friendly_packages repository does not exist. Please run /lib /add <library_name> command first to clone it.")
|
|
3009
|
-
return
|
|
3010
|
-
|
|
3011
|
-
available_libs = []
|
|
3012
|
-
|
|
3013
|
-
# 遍历所有domain目录
|
|
3014
|
-
for domain in os.listdir(llm_friendly_packages_dir):
|
|
3015
|
-
domain_path = os.path.join(llm_friendly_packages_dir, domain)
|
|
3016
|
-
if os.path.isdir(domain_path):
|
|
3017
|
-
# 遍历所有username目录
|
|
3018
|
-
for username in os.listdir(domain_path):
|
|
3019
|
-
username_path = os.path.join(domain_path, username)
|
|
3020
|
-
if os.path.isdir(username_path):
|
|
3021
|
-
# 遍历所有lib_name目录
|
|
3022
|
-
for lib_name in os.listdir(username_path):
|
|
3023
|
-
lib_path = os.path.join(username_path, lib_name)
|
|
3024
|
-
if os.path.isdir(lib_path):
|
|
3025
|
-
# 检查是否有Markdown文件
|
|
3026
|
-
has_md_files = False
|
|
3027
|
-
for root, _, files in os.walk(lib_path):
|
|
3028
|
-
if any(file.endswith('.md') for file in files):
|
|
3029
|
-
has_md_files = True
|
|
3030
|
-
break
|
|
3031
|
-
|
|
3032
|
-
if has_md_files:
|
|
3033
|
-
available_libs.append({
|
|
3034
|
-
"domain": domain,
|
|
3035
|
-
"username": username,
|
|
3036
|
-
"lib_name": lib_name,
|
|
3037
|
-
"full_path": f"{username}/{lib_name}",
|
|
3038
|
-
"is_added": lib_name in memory["libs"]
|
|
3039
|
-
})
|
|
3040
|
-
|
|
3041
|
-
if available_libs:
|
|
3042
|
-
table = Table(title="Available Libraries")
|
|
3043
|
-
table.add_column("Domain", style="blue")
|
|
3044
|
-
table.add_column("Username", style="green")
|
|
3045
|
-
table.add_column("Library Name", style="cyan")
|
|
3046
|
-
table.add_column("Full Path", style="magenta")
|
|
3047
|
-
table.add_column("Status", style="yellow")
|
|
3048
|
-
|
|
3049
|
-
# 按domain和username分组排序
|
|
3050
|
-
available_libs.sort(key=lambda x: (x["domain"], x["username"], x["lib_name"]))
|
|
3051
|
-
|
|
3052
|
-
for lib in available_libs:
|
|
3053
|
-
status = "[green]Added[/green]" if lib["is_added"] else "[white]Not Added[/white]"
|
|
3054
|
-
table.add_row(
|
|
3055
|
-
lib["domain"],
|
|
3056
|
-
lib["username"],
|
|
3057
|
-
lib["lib_name"],
|
|
3058
|
-
lib["full_path"],
|
|
3059
|
-
status
|
|
3060
|
-
)
|
|
3061
|
-
|
|
3062
|
-
console.print(table)
|
|
3063
|
-
else:
|
|
3064
|
-
console.print("No available libraries found in the repository.")
|
|
3065
|
-
|
|
3066
|
-
elif subcommand == "/set-proxy":
|
|
3067
|
-
if len(args) == 1:
|
|
3068
|
-
current_proxy = memory.get("lib-proxy", "No proxy set")
|
|
3069
|
-
console.print(f"Current proxy: {current_proxy}")
|
|
3070
|
-
elif len(args) == 2:
|
|
3071
|
-
proxy_url = args[1]
|
|
3072
|
-
memory["lib-proxy"] = proxy_url
|
|
3073
|
-
console.print(f"Set proxy to: {proxy_url}")
|
|
3074
|
-
save_memory()
|
|
3075
|
-
else:
|
|
3076
|
-
console.print("Invalid number of arguments for /set-proxy")
|
|
3077
|
-
|
|
3078
|
-
elif subcommand == "/refresh":
|
|
3079
|
-
if os.path.exists(llm_friendly_packages_dir):
|
|
3080
|
-
try:
|
|
3081
|
-
repo = git.Repo(llm_friendly_packages_dir)
|
|
3082
|
-
origin = repo.remotes.origin
|
|
3083
|
-
proxy_url = memory.get("lib-proxy")
|
|
3084
|
-
|
|
3085
|
-
current_url = origin.url
|
|
3086
|
-
|
|
3087
|
-
if proxy_url and proxy_url != current_url:
|
|
3088
|
-
new_url = proxy_url
|
|
3089
|
-
origin.set_url(new_url)
|
|
3090
|
-
console.print(f"Updated remote URL to: {new_url}")
|
|
3091
|
-
|
|
3092
|
-
origin.pull()
|
|
3093
|
-
console.print(
|
|
3094
|
-
"Successfully updated llm_friendly_packages repository")
|
|
3095
|
-
|
|
3096
|
-
except git.exc.GitCommandError as e:
|
|
3097
|
-
console.print(f"Error updating repository: {e}")
|
|
3098
|
-
else:
|
|
3099
|
-
console.print(
|
|
3100
|
-
"llm_friendly_packages repository does not exist. Please run /lib /add <library_name> command first to clone it."
|
|
3101
|
-
)
|
|
1761
|
+
"""
|
|
1762
|
+
处理库管理命令,使用 LibHandler 进行统一处理
|
|
3102
1763
|
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
package_name = args[1].strip()
|
|
3108
|
-
docs = get_llm_friendly_package_docs(package_name, return_paths=True)
|
|
3109
|
-
if docs:
|
|
3110
|
-
table = Table(title=f"Markdown Files for {package_name}")
|
|
3111
|
-
table.add_column("File Path", style="cyan")
|
|
3112
|
-
for doc in docs:
|
|
3113
|
-
table.add_row(doc)
|
|
3114
|
-
console.print(table)
|
|
3115
|
-
else:
|
|
3116
|
-
console.print(
|
|
3117
|
-
f"No markdown files found for package: {package_name}")
|
|
1764
|
+
Args:
|
|
1765
|
+
args: 命令参数列表
|
|
1766
|
+
"""
|
|
1767
|
+
from autocoder.common.file_handler import LibHandler
|
|
3118
1768
|
|
|
3119
|
-
|
|
3120
|
-
|
|
1769
|
+
handler = LibHandler()
|
|
1770
|
+
handler.handle_lib_command(args)
|
|
3121
1771
|
|
|
3122
1772
|
|
|
3123
1773
|
def execute_shell_command(command: str):
|
|
3124
1774
|
from autocoder.common.shells import execute_shell_command as shell_exec
|
|
1775
|
+
|
|
3125
1776
|
shell_exec(command)
|
|
3126
1777
|
|
|
3127
1778
|
|
|
3128
1779
|
def conf_export(path: str):
|
|
3129
1780
|
from autocoder.common.conf_import_export import export_conf
|
|
1781
|
+
|
|
3130
1782
|
export_conf(os.getcwd(), path)
|
|
3131
1783
|
|
|
1784
|
+
|
|
3132
1785
|
def conf_import(path: str):
|
|
3133
1786
|
from autocoder.common.conf_import_export import import_conf
|
|
1787
|
+
|
|
3134
1788
|
import_conf(os.getcwd(), path)
|
|
3135
1789
|
|
|
1790
|
+
|
|
3136
1791
|
def generate_new_yaml(query: str):
|
|
3137
1792
|
memory = get_memory()
|
|
3138
|
-
conf = memory.get("conf",{})
|
|
3139
|
-
current_files = memory.get("current_files",{}).get("files",[])
|
|
3140
|
-
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"])
|
|
3141
1796
|
latest_yaml_file = get_last_yaml_file("actions")
|
|
3142
1797
|
if latest_yaml_file:
|
|
3143
1798
|
yaml_config = {
|
|
@@ -3147,11 +1802,11 @@ def generate_new_yaml(query: str):
|
|
|
3147
1802
|
"skip_build_index": conf.get("skip_build_index", "true") == "true",
|
|
3148
1803
|
"skip_confirm": conf.get("skip_confirm", "true") == "true",
|
|
3149
1804
|
"silence": conf.get("silence", "true") == "true",
|
|
3150
|
-
"include_project_structure": conf.get("include_project_structure", "
|
|
1805
|
+
"include_project_structure": conf.get("include_project_structure", "false")
|
|
3151
1806
|
== "true",
|
|
3152
1807
|
"exclude_files": memory.get("exclude_files", []),
|
|
3153
1808
|
}
|
|
3154
|
-
yaml_config["context"] = ""
|
|
1809
|
+
yaml_config["context"] = ""
|
|
3155
1810
|
for key, value in conf.items():
|
|
3156
1811
|
converted_value = convert_config_value(key, value)
|
|
3157
1812
|
if converted_value is not None:
|
|
@@ -3162,294 +1817,356 @@ def generate_new_yaml(query: str):
|
|
|
3162
1817
|
)
|
|
3163
1818
|
# handle image
|
|
3164
1819
|
v = Image.convert_image_paths_from(query)
|
|
3165
|
-
yaml_config["query"] = v
|
|
1820
|
+
yaml_config["query"] = v
|
|
3166
1821
|
|
|
3167
|
-
yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
|
|
1822
|
+
yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
|
|
3168
1823
|
|
|
3169
1824
|
execute_file = os.path.join("actions", latest_yaml_file)
|
|
3170
|
-
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:
|
|
3171
1826
|
f.write(yaml_content)
|
|
3172
|
-
return execute_file,convert_yaml_to_config(execute_file)
|
|
3173
|
-
|
|
3174
|
-
@run_in_raw_thread()
|
|
3175
|
-
def auto_command(query: str,extra_args: Dict[str,Any]={}):
|
|
3176
|
-
"""处理/auto指令"""
|
|
3177
|
-
args = get_final_config()
|
|
3178
|
-
memory = get_memory()
|
|
3179
|
-
if args.enable_agentic_edit:
|
|
3180
|
-
from autocoder.run_context import get_run_context,RunMode
|
|
3181
|
-
execute_file,args = generate_new_yaml(query)
|
|
3182
|
-
args.file = execute_file
|
|
3183
|
-
current_files = memory.get("current_files",{}).get("files",[])
|
|
3184
|
-
sources = []
|
|
3185
|
-
for file in current_files:
|
|
3186
|
-
try:
|
|
3187
|
-
with open(file,"r",encoding="utf-8") as f:
|
|
3188
|
-
sources.append(SourceCode(module_name=file,source_code=f.read()))
|
|
3189
|
-
except Exception as e:
|
|
3190
|
-
global_logger.error(f"Failed to read file {file}: {e}")
|
|
3191
|
-
|
|
3192
|
-
llm = get_single_llm(args.code_model or args.model,product_mode=args.product_mode)
|
|
3193
|
-
conversation_history = extra_args.get("conversations",[])
|
|
1827
|
+
return execute_file, convert_yaml_to_config(execute_file)
|
|
3194
1828
|
|
|
3195
|
-
command_infos = parse_query(query)
|
|
3196
1829
|
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
)
|
|
3201
|
-
|
|
3202
|
-
## web 模式会自己管理对话,所以这里总是设置为新对话
|
|
3203
|
-
if get_run_context().mode == RunMode.WEB:
|
|
3204
|
-
command_infos = {
|
|
3205
|
-
"new":{
|
|
3206
|
-
"args":[query]
|
|
3207
|
-
}
|
|
3208
|
-
}
|
|
3209
|
-
|
|
3210
|
-
task_query = query
|
|
3211
|
-
|
|
3212
|
-
if "new" in command_infos:
|
|
3213
|
-
conversation_config.action = "new"
|
|
3214
|
-
task_query = " ".join(command_infos["new"]["args"])
|
|
3215
|
-
|
|
3216
|
-
if "resume" in command_infos:
|
|
3217
|
-
conversation_config.action = "resume"
|
|
3218
|
-
conversation_config.conversation_id = command_infos["resume"]["args"][0]
|
|
3219
|
-
task_query = " ".join(command_infos["resume"]["args"][1:])
|
|
1830
|
+
def handle_conversation_actions(conversation_config) -> bool:
|
|
1831
|
+
"""
|
|
1832
|
+
处理对话列表和创建新对话的操作
|
|
3220
1833
|
|
|
3221
|
-
|
|
3222
|
-
|
|
1834
|
+
Args:
|
|
1835
|
+
conversation_config: 对话配置对象
|
|
3223
1836
|
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
1837
|
+
Returns:
|
|
1838
|
+
bool: 如果处理了特殊操作(LIST或NEW without input)返回True,否则返回False
|
|
1839
|
+
"""
|
|
1840
|
+
if not conversation_config:
|
|
1841
|
+
return False
|
|
3228
1842
|
|
|
3229
|
-
|
|
1843
|
+
console = Console()
|
|
3230
1844
|
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
completer.refresh_files()
|
|
3245
|
-
return
|
|
3246
|
-
|
|
3247
|
-
args = get_final_config()
|
|
3248
|
-
# 准备请求参数
|
|
3249
|
-
request = AutoCommandRequest(
|
|
3250
|
-
user_input=query
|
|
3251
|
-
)
|
|
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)
|
|
3252
1857
|
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
commit=commit,
|
|
3265
|
-
help=help,
|
|
3266
|
-
exclude_dirs=exclude_dirs,
|
|
3267
|
-
exclude_files=exclude_files,
|
|
3268
|
-
ask=ask,
|
|
3269
|
-
chat=chat,
|
|
3270
|
-
coding=coding,
|
|
3271
|
-
design=design,
|
|
3272
|
-
summon=summon,
|
|
3273
|
-
lib=lib_command,
|
|
3274
|
-
mcp=mcp,
|
|
3275
|
-
models=manage_models,
|
|
3276
|
-
index_build=index_build,
|
|
3277
|
-
index_query=index_query,
|
|
3278
|
-
execute_shell_command=execute_shell_command,
|
|
3279
|
-
generate_shell_command=generate_shell_command,
|
|
3280
|
-
conf_export=conf_export,
|
|
3281
|
-
conf_import=conf_import,
|
|
3282
|
-
index_export=index_export,
|
|
3283
|
-
index_import=index_import
|
|
3284
|
-
))
|
|
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
|
|
3285
1869
|
|
|
3286
|
-
#
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
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()}"
|
|
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
|
|
3298
1956
|
|
|
3299
1957
|
|
|
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
|
|
3300
1965
|
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
pr:bool=False,
|
|
3305
|
-
extra_args: Dict[str,Any]={}
|
|
3306
|
-
):
|
|
3307
|
-
"""处理/auto指令"""
|
|
3308
|
-
args = get_final_config()
|
|
3309
|
-
memory = get_memory()
|
|
3310
|
-
if args.enable_agentic_edit:
|
|
3311
|
-
from autocoder.run_context import get_run_context,RunMode
|
|
3312
|
-
execute_file,args = generate_new_yaml(query)
|
|
3313
|
-
args.file = execute_file
|
|
3314
|
-
current_files = memory.get("current_files",{}).get("files",[])
|
|
1966
|
+
execute_file, _ = generate_new_yaml(query)
|
|
1967
|
+
args.file = execute_file
|
|
1968
|
+
current_files = memory.get("current_files", {}).get("files", [])
|
|
3315
1969
|
sources = []
|
|
3316
1970
|
for file in current_files:
|
|
3317
1971
|
try:
|
|
3318
|
-
with open(file,"r",encoding="utf-8") as f:
|
|
3319
|
-
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()))
|
|
3320
1974
|
except Exception as e:
|
|
3321
1975
|
global_logger.error(f"Failed to read file {file}: {e}")
|
|
3322
|
-
|
|
3323
|
-
llm = get_single_llm(args.code_model or args.model,product_mode=args.product_mode)
|
|
3324
|
-
conversation_history = extra_args.get("conversations",[])
|
|
3325
1976
|
|
|
3326
|
-
|
|
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)
|
|
3327
1995
|
|
|
3328
1996
|
# terminal 的总是接着上次对话, 所以这里总是设置为 resume
|
|
3329
1997
|
conversation_config = AgenticEditConversationConfig(
|
|
3330
|
-
action=
|
|
1998
|
+
action=ConversationAction.RESUME
|
|
3331
1999
|
)
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
"args":[query]
|
|
3338
|
-
}
|
|
3339
|
-
}
|
|
3340
|
-
|
|
3341
|
-
task_query = query
|
|
3342
|
-
|
|
3343
|
-
if "new" in command_infos:
|
|
3344
|
-
conversation_config.action = "new"
|
|
2000
|
+
|
|
2001
|
+
task_query = query
|
|
2002
|
+
|
|
2003
|
+
if "new" in command_infos:
|
|
2004
|
+
conversation_config.action = ConversationAction.NEW
|
|
3345
2005
|
task_query = " ".join(command_infos["new"]["args"])
|
|
3346
|
-
|
|
2006
|
+
|
|
3347
2007
|
if "resume" in command_infos:
|
|
3348
|
-
conversation_config.action =
|
|
3349
|
-
conversation_config.conversation_id = command_infos["resume"]["args"][0]
|
|
3350
|
-
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:])
|
|
3351
2011
|
|
|
3352
2012
|
if "list" in command_infos:
|
|
3353
|
-
conversation_config.action =
|
|
2013
|
+
conversation_config.action = ConversationAction.LIST
|
|
3354
2014
|
|
|
3355
|
-
|
|
3356
2015
|
if "command" in command_infos:
|
|
3357
|
-
conversation_config.action =
|
|
2016
|
+
conversation_config.action = ConversationAction.COMMAND
|
|
3358
2017
|
task_query = render_command_file_with_variables(command_infos)
|
|
3359
|
-
|
|
3360
|
-
conversation_config.query = task_query
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
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
|
+
|
|
3382
2085
|
completer.refresh_files()
|
|
3383
|
-
return
|
|
3384
|
-
|
|
3385
|
-
args = get_final_config()
|
|
2086
|
+
return conversation_config.conversation_id
|
|
2087
|
+
|
|
2088
|
+
args = get_final_config()
|
|
3386
2089
|
# 准备请求参数
|
|
3387
|
-
request = AutoCommandRequest(
|
|
3388
|
-
user_input=query
|
|
3389
|
-
)
|
|
2090
|
+
request = AutoCommandRequest(user_input=query)
|
|
3390
2091
|
|
|
3391
2092
|
# 初始化调优器
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
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
|
+
)
|
|
3423
2140
|
|
|
3424
2141
|
# 生成建议
|
|
3425
2142
|
response = tuner.analyze(request)
|
|
3426
2143
|
printer = Printer()
|
|
3427
2144
|
# 显示建议
|
|
3428
|
-
console = Console()
|
|
3429
|
-
console.print(
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
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
|
+
)
|
|
3440
2156
|
completer.refresh_files()
|
|
2157
|
+
return None
|
|
3441
2158
|
|
|
3442
2159
|
|
|
3443
2160
|
def render_command_file_with_variables(command_infos: Dict[str, Any]) -> str:
|
|
3444
2161
|
"""
|
|
3445
2162
|
使用 CommandManager 加载并渲染命令文件
|
|
3446
|
-
|
|
2163
|
+
|
|
3447
2164
|
Args:
|
|
3448
2165
|
command_infos: parse_query(query) 的返回结果,包含命令和参数信息
|
|
3449
|
-
|
|
2166
|
+
|
|
3450
2167
|
Returns:
|
|
3451
2168
|
str: 渲染后的文件内容
|
|
3452
|
-
|
|
2169
|
+
|
|
3453
2170
|
Raises:
|
|
3454
2171
|
ValueError: 当参数不足或文件不存在时
|
|
3455
2172
|
Exception: 当渲染过程出现错误时
|
|
@@ -3458,31 +2175,33 @@ def render_command_file_with_variables(command_infos: Dict[str, Any]) -> str:
|
|
|
3458
2175
|
# 获取第一个命令的信息
|
|
3459
2176
|
if not command_infos:
|
|
3460
2177
|
raise ValueError("command_infos 为空,无法获取命令信息")
|
|
3461
|
-
|
|
2178
|
+
|
|
3462
2179
|
# command 的位置参数作为路径
|
|
3463
2180
|
first_command = command_infos["command"]
|
|
3464
|
-
|
|
2181
|
+
|
|
3465
2182
|
# 获取位置参数(文件路径)
|
|
3466
2183
|
args = first_command.get("args", [])
|
|
3467
2184
|
if not args:
|
|
3468
2185
|
raise ValueError("未提供文件路径参数")
|
|
3469
|
-
|
|
2186
|
+
|
|
3470
2187
|
file_path = args[0] # 第一个位置参数作为文件路径
|
|
3471
|
-
|
|
2188
|
+
|
|
3472
2189
|
# 获取关键字参数作为渲染参数
|
|
3473
2190
|
kwargs = first_command.get("kwargs", {})
|
|
3474
|
-
|
|
2191
|
+
|
|
3475
2192
|
# 初始化 CommandManager
|
|
3476
2193
|
command_manager = CommandManager()
|
|
3477
|
-
|
|
2194
|
+
|
|
3478
2195
|
# 使用 read_command_file_with_render 直接读取并渲染命令文件
|
|
3479
|
-
rendered_content = command_manager.read_command_file_with_render(
|
|
2196
|
+
rendered_content = command_manager.read_command_file_with_render(
|
|
2197
|
+
file_path, kwargs
|
|
2198
|
+
)
|
|
3480
2199
|
if rendered_content is None:
|
|
3481
2200
|
raise ValueError(f"无法读取或渲染命令文件: {file_path}")
|
|
3482
|
-
|
|
2201
|
+
|
|
3483
2202
|
global_logger.info(f"成功渲染命令文件: {file_path}, 使用参数: {kwargs}")
|
|
3484
2203
|
return rendered_content
|
|
3485
|
-
|
|
2204
|
+
|
|
3486
2205
|
except Exception as e:
|
|
3487
2206
|
global_logger.error(f"render_command_file_with_variables 执行失败: {str(e)}")
|
|
3488
|
-
raise
|
|
2207
|
+
raise
|