auto-coder 1.0.0__py3-none-any.whl → 2.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of auto-coder might be problematic. Click here for more details.
- auto_coder-2.0.0.dist-info/LICENSE +158 -0
- auto_coder-2.0.0.dist-info/METADATA +558 -0
- auto_coder-2.0.0.dist-info/RECORD +795 -0
- {auto_coder-1.0.0.dist-info → auto_coder-2.0.0.dist-info}/WHEEL +1 -1
- {auto_coder-1.0.0.dist-info → auto_coder-2.0.0.dist-info}/entry_points.txt +3 -3
- autocoder/__init__.py +31 -0
- autocoder/agent/auto_filegroup.py +32 -13
- autocoder/agent/auto_learn_from_commit.py +9 -1
- autocoder/agent/base_agentic/__init__.py +3 -0
- autocoder/agent/base_agentic/agent_hub.py +1 -1
- autocoder/agent/base_agentic/base_agent.py +235 -136
- autocoder/agent/base_agentic/default_tools.py +119 -118
- autocoder/agent/base_agentic/test_base_agent.py +1 -1
- autocoder/agent/base_agentic/tool_registry.py +32 -20
- autocoder/agent/base_agentic/tools/read_file_tool_resolver.py +24 -3
- autocoder/agent/base_agentic/tools/write_to_file_tool_resolver.py +24 -11
- autocoder/agent/base_agentic/types.py +42 -0
- autocoder/agent/entry_command_agent/chat.py +73 -59
- autocoder/auto_coder.py +31 -40
- autocoder/auto_coder_rag.py +11 -1084
- autocoder/auto_coder_runner.py +970 -2345
- autocoder/auto_coder_terminal.py +26 -0
- autocoder/auto_coder_terminal_v3.py +190 -0
- autocoder/chat/conf_command.py +224 -124
- autocoder/chat/models_command.py +361 -299
- autocoder/chat/rules_command.py +79 -31
- autocoder/chat_auto_coder.py +988 -398
- autocoder/chat_auto_coder_lang.py +23 -732
- autocoder/commands/auto_command.py +25 -8
- autocoder/commands/auto_web.py +1 -1
- autocoder/commands/tools.py +44 -44
- autocoder/common/__init__.py +150 -128
- autocoder/common/ac_style_command_parser/__init__.py +39 -2
- autocoder/common/ac_style_command_parser/config.py +422 -0
- autocoder/common/ac_style_command_parser/parser.py +292 -78
- autocoder/common/ac_style_command_parser/test_parser.py +241 -16
- autocoder/common/ac_style_command_parser/test_typed_parser.py +342 -0
- autocoder/common/ac_style_command_parser/typed_parser.py +653 -0
- autocoder/common/action_yml_file_manager.py +25 -13
- autocoder/common/agent_events/__init__.py +52 -0
- autocoder/common/agent_events/agent_event_emitter.py +193 -0
- autocoder/common/agent_events/event_factory.py +177 -0
- autocoder/common/agent_events/examples.py +307 -0
- autocoder/common/agent_events/types.py +113 -0
- autocoder/common/agent_events/utils.py +68 -0
- autocoder/common/agent_hooks/__init__.py +44 -0
- autocoder/common/agent_hooks/examples.py +582 -0
- autocoder/common/agent_hooks/hook_executor.py +217 -0
- autocoder/common/agent_hooks/hook_manager.py +288 -0
- autocoder/common/agent_hooks/types.py +133 -0
- autocoder/common/agent_hooks/utils.py +99 -0
- autocoder/common/agent_query_queue/queue_executor.py +324 -0
- autocoder/common/agent_query_queue/queue_manager.py +325 -0
- autocoder/common/agents/__init__.py +11 -0
- autocoder/common/agents/agent_manager.py +323 -0
- autocoder/common/agents/agent_parser.py +189 -0
- autocoder/common/agents/example_usage.py +344 -0
- autocoder/common/agents/integration_example.py +330 -0
- autocoder/common/agents/test_agent_parser.py +545 -0
- autocoder/common/async_utils.py +101 -0
- autocoder/common/auto_coder_lang.py +23 -972
- autocoder/common/autocoderargs_parser/__init__.py +14 -0
- autocoder/common/autocoderargs_parser/parser.py +184 -0
- autocoder/common/autocoderargs_parser/tests/__init__.py +1 -0
- autocoder/common/autocoderargs_parser/tests/test_args_parser.py +235 -0
- autocoder/common/autocoderargs_parser/tests/test_token_parser.py +195 -0
- autocoder/common/autocoderargs_parser/token_parser.py +290 -0
- autocoder/common/buildin_tokenizer.py +2 -4
- autocoder/common/code_auto_generate.py +149 -74
- autocoder/common/code_auto_generate_diff.py +163 -70
- autocoder/common/code_auto_generate_editblock.py +179 -89
- autocoder/common/code_auto_generate_strict_diff.py +167 -72
- autocoder/common/code_auto_merge_editblock.py +13 -6
- autocoder/common/code_modification_ranker.py +1 -1
- autocoder/common/command_completer.py +3 -3
- autocoder/common/command_file_manager/manager.py +183 -47
- autocoder/common/command_file_manager/test_command_file_manager.py +507 -0
- autocoder/common/command_templates.py +1 -1
- autocoder/common/conf_utils.py +2 -4
- autocoder/common/conversations/config.py +11 -3
- autocoder/common/conversations/get_conversation_manager.py +100 -2
- autocoder/common/conversations/llm_stats_models.py +264 -0
- autocoder/common/conversations/manager.py +112 -28
- autocoder/common/conversations/models.py +16 -2
- autocoder/common/conversations/storage/index_manager.py +134 -10
- autocoder/common/core_config/__init__.py +63 -0
- autocoder/common/core_config/agentic_mode_manager.py +109 -0
- autocoder/common/core_config/base_manager.py +123 -0
- autocoder/common/core_config/compatibility.py +151 -0
- autocoder/common/core_config/config_manager.py +156 -0
- autocoder/common/core_config/conversation_manager.py +31 -0
- autocoder/common/core_config/exclude_manager.py +72 -0
- autocoder/common/core_config/file_manager.py +177 -0
- autocoder/common/core_config/human_as_model_manager.py +129 -0
- autocoder/common/core_config/lib_manager.py +54 -0
- autocoder/common/core_config/main_manager.py +81 -0
- autocoder/common/core_config/mode_manager.py +126 -0
- autocoder/common/core_config/models.py +70 -0
- autocoder/common/core_config/test_memory_manager.py +1056 -0
- autocoder/common/env_manager.py +282 -0
- autocoder/common/env_manager_usage_example.py +211 -0
- autocoder/common/file_checkpoint/conversation_checkpoint.py +19 -19
- autocoder/common/file_checkpoint/manager.py +264 -48
- autocoder/common/file_checkpoint/test_backup.py +1 -18
- autocoder/common/file_checkpoint/test_manager.py +270 -1
- autocoder/common/file_checkpoint/test_store.py +1 -17
- autocoder/common/file_handler/__init__.py +23 -0
- autocoder/common/file_handler/active_context_handler.py +159 -0
- autocoder/common/file_handler/add_files_handler.py +409 -0
- autocoder/common/file_handler/chat_handler.py +180 -0
- autocoder/common/file_handler/coding_handler.py +401 -0
- autocoder/common/file_handler/commit_handler.py +200 -0
- autocoder/common/file_handler/lib_handler.py +156 -0
- autocoder/common/file_handler/list_files_handler.py +111 -0
- autocoder/common/file_handler/mcp_handler.py +268 -0
- autocoder/common/file_handler/models_handler.py +493 -0
- autocoder/common/file_handler/remove_files_handler.py +172 -0
- autocoder/common/git_utils.py +44 -8
- autocoder/common/global_cancel.py +15 -6
- autocoder/common/ignorefiles/test_ignore_file_utils.py +1 -1
- autocoder/common/international/__init__.py +31 -0
- autocoder/common/international/demo_international.py +92 -0
- autocoder/common/international/message_manager.py +157 -0
- autocoder/common/international/messages/__init__.py +56 -0
- autocoder/common/international/messages/async_command_messages.py +507 -0
- autocoder/common/international/messages/auto_coder_messages.py +2208 -0
- autocoder/common/international/messages/chat_auto_coder_messages.py +1547 -0
- autocoder/common/international/messages/command_help_messages.py +986 -0
- autocoder/common/international/messages/conversation_command_messages.py +191 -0
- autocoder/common/international/messages/git_helper_plugin_messages.py +159 -0
- autocoder/common/international/messages/queue_command_messages.py +751 -0
- autocoder/common/international/messages/rules_command_messages.py +77 -0
- autocoder/common/international/messages/sdk_messages.py +1707 -0
- autocoder/common/international/messages/token_helper_plugin_messages.py +361 -0
- autocoder/common/international/messages/tool_display_messages.py +1212 -0
- autocoder/common/international/messages/workflow_exception_messages.py +473 -0
- autocoder/common/international/test_international.py +612 -0
- autocoder/common/linter_core/__init__.py +28 -0
- autocoder/common/linter_core/base_linter.py +61 -0
- autocoder/common/linter_core/config_loader.py +271 -0
- autocoder/common/linter_core/formatters/__init__.py +0 -0
- autocoder/common/linter_core/formatters/base_formatter.py +38 -0
- autocoder/common/linter_core/formatters/raw_formatter.py +17 -0
- autocoder/common/linter_core/linter.py +166 -0
- autocoder/common/linter_core/linter_factory.py +216 -0
- autocoder/common/linter_core/linter_manager.py +333 -0
- autocoder/common/linter_core/linters/__init__.py +9 -0
- autocoder/common/linter_core/linters/java_linter.py +342 -0
- autocoder/common/linter_core/linters/python_linter.py +115 -0
- autocoder/common/linter_core/linters/typescript_linter.py +119 -0
- autocoder/common/linter_core/models/__init__.py +7 -0
- autocoder/common/linter_core/models/lint_result.py +91 -0
- autocoder/common/linter_core/models.py +33 -0
- autocoder/common/linter_core/tests/__init__.py +3 -0
- autocoder/common/linter_core/tests/test_config_loader.py +323 -0
- autocoder/common/linter_core/tests/test_config_loading.py +308 -0
- autocoder/common/linter_core/tests/test_factory_manager.py +234 -0
- autocoder/common/linter_core/tests/test_formatters.py +147 -0
- autocoder/common/linter_core/tests/test_integration.py +317 -0
- autocoder/common/linter_core/tests/test_java_linter.py +496 -0
- autocoder/common/linter_core/tests/test_linters.py +265 -0
- autocoder/common/linter_core/tests/test_models.py +81 -0
- autocoder/common/linter_core/tests/verify_config_loading.py +296 -0
- autocoder/common/linter_core/tests/verify_fixes.py +183 -0
- autocoder/common/llm_friendly_package/__init__.py +31 -0
- autocoder/common/llm_friendly_package/base_manager.py +102 -0
- autocoder/common/llm_friendly_package/docs_manager.py +121 -0
- autocoder/common/llm_friendly_package/library_manager.py +171 -0
- autocoder/common/{llm_friendly_package.py → llm_friendly_package/main_manager.py} +204 -231
- autocoder/common/llm_friendly_package/models.py +40 -0
- autocoder/common/llm_friendly_package/test_llm_friendly_package.py +536 -0
- autocoder/common/llms/__init__.py +15 -0
- autocoder/common/llms/demo_error_handling.py +85 -0
- autocoder/common/llms/factory.py +142 -0
- autocoder/common/llms/manager.py +264 -0
- autocoder/common/llms/pricing.py +121 -0
- autocoder/common/llms/registry.py +288 -0
- autocoder/common/llms/schema.py +77 -0
- autocoder/common/llms/simple_demo.py +45 -0
- autocoder/common/llms/test_quick_model.py +116 -0
- autocoder/common/llms/test_remove_functionality.py +182 -0
- autocoder/common/llms/tests/__init__.py +1 -0
- autocoder/common/llms/tests/test_manager.py +330 -0
- autocoder/common/llms/tests/test_registry.py +364 -0
- autocoder/common/mcp_tools/__init__.py +62 -0
- autocoder/common/{mcp_tools.py → mcp_tools/executor.py} +49 -40
- autocoder/common/{mcp_hub.py → mcp_tools/hub.py} +42 -68
- autocoder/common/{mcp_server_install.py → mcp_tools/installer.py} +16 -28
- autocoder/common/{mcp_server.py → mcp_tools/server.py} +176 -48
- autocoder/common/mcp_tools/test_keyboard_interrupt.py +93 -0
- autocoder/common/mcp_tools/test_mcp_tools.py +391 -0
- autocoder/common/{mcp_server_types.py → mcp_tools/types.py} +121 -48
- autocoder/common/mcp_tools/verify_functionality.py +202 -0
- autocoder/common/model_speed_tester.py +32 -26
- autocoder/common/priority_directory_finder/__init__.py +142 -0
- autocoder/common/priority_directory_finder/examples.py +230 -0
- autocoder/common/priority_directory_finder/finder.py +283 -0
- autocoder/common/priority_directory_finder/models.py +236 -0
- autocoder/common/priority_directory_finder/test_priority_directory_finder.py +431 -0
- autocoder/common/project_scanner/__init__.py +18 -0
- autocoder/common/project_scanner/compat.py +77 -0
- autocoder/common/project_scanner/scanner.py +436 -0
- autocoder/common/project_tracker/__init__.py +27 -0
- autocoder/common/project_tracker/api.py +228 -0
- autocoder/common/project_tracker/demo.py +272 -0
- autocoder/common/project_tracker/tracker.py +487 -0
- autocoder/common/project_tracker/types.py +53 -0
- autocoder/common/pruner/__init__.py +67 -0
- autocoder/common/pruner/agentic_conversation_pruner.py +651 -102
- autocoder/common/pruner/conversation_message_ids_api.py +386 -0
- autocoder/common/pruner/conversation_message_ids_manager.py +347 -0
- autocoder/common/pruner/conversation_message_ids_pruner.py +473 -0
- autocoder/common/pruner/conversation_normalizer.py +347 -0
- autocoder/common/pruner/conversation_pruner.py +26 -6
- autocoder/common/pruner/test_agentic_conversation_pruner.py +554 -112
- autocoder/common/pruner/test_conversation_normalizer.py +502 -0
- autocoder/common/pruner/test_tool_content_detector.py +324 -0
- autocoder/common/pruner/tool_content_detector.py +227 -0
- autocoder/common/pruner/tools/__init__.py +18 -0
- autocoder/common/pruner/tools/query_message_ids.py +264 -0
- autocoder/common/pruner/tools/test_agentic_pruning_logic.py +432 -0
- autocoder/common/pruner/tools/test_message_ids_pruning_only.py +192 -0
- autocoder/common/pull_requests/__init__.py +9 -1
- autocoder/common/pull_requests/utils.py +122 -1
- autocoder/common/rag_manager/rag_manager.py +36 -40
- autocoder/common/rulefiles/__init__.py +53 -1
- autocoder/common/rulefiles/api.py +250 -0
- autocoder/common/rulefiles/core/__init__.py +14 -0
- autocoder/common/rulefiles/core/manager.py +241 -0
- autocoder/common/rulefiles/core/selector.py +805 -0
- autocoder/common/rulefiles/models/__init__.py +20 -0
- autocoder/common/rulefiles/models/index.py +16 -0
- autocoder/common/rulefiles/models/init_rule.py +18 -0
- autocoder/common/rulefiles/models/rule_file.py +18 -0
- autocoder/common/rulefiles/models/rule_relevance.py +14 -0
- autocoder/common/rulefiles/models/summary.py +16 -0
- autocoder/common/rulefiles/test_rulefiles.py +776 -0
- autocoder/common/rulefiles/utils/__init__.py +34 -0
- autocoder/common/rulefiles/utils/monitor.py +86 -0
- autocoder/common/rulefiles/utils/parser.py +230 -0
- autocoder/common/save_formatted_log.py +67 -10
- autocoder/common/search_replace.py +8 -1
- autocoder/common/search_replace_patch/__init__.py +24 -0
- autocoder/common/search_replace_patch/base.py +115 -0
- autocoder/common/search_replace_patch/manager.py +248 -0
- autocoder/common/search_replace_patch/patch_replacer.py +304 -0
- autocoder/common/search_replace_patch/similarity_replacer.py +306 -0
- autocoder/common/search_replace_patch/string_replacer.py +181 -0
- autocoder/common/search_replace_patch/tests/__init__.py +3 -0
- autocoder/common/search_replace_patch/tests/run_tests.py +126 -0
- autocoder/common/search_replace_patch/tests/test_base.py +188 -0
- autocoder/common/search_replace_patch/tests/test_empty_line_insert.py +233 -0
- autocoder/common/search_replace_patch/tests/test_integration.py +389 -0
- autocoder/common/search_replace_patch/tests/test_manager.py +351 -0
- autocoder/common/search_replace_patch/tests/test_patch_replacer.py +316 -0
- autocoder/common/search_replace_patch/tests/test_regex_replacer.py +306 -0
- autocoder/common/search_replace_patch/tests/test_similarity_replacer.py +384 -0
- autocoder/common/shell_commands/__init__.py +197 -0
- autocoder/common/shell_commands/background_process_notifier.py +346 -0
- autocoder/common/shell_commands/command_executor.py +1127 -0
- autocoder/common/shell_commands/error_recovery.py +541 -0
- autocoder/common/shell_commands/exceptions.py +120 -0
- autocoder/common/shell_commands/interactive_executor.py +476 -0
- autocoder/common/shell_commands/interactive_pexpect_process.py +623 -0
- autocoder/common/shell_commands/interactive_process.py +744 -0
- autocoder/common/shell_commands/interactive_session_manager.py +1014 -0
- autocoder/common/shell_commands/monitoring.py +529 -0
- autocoder/common/shell_commands/process_cleanup.py +386 -0
- autocoder/common/shell_commands/process_manager.py +606 -0
- autocoder/common/shell_commands/test_interactive_pexpect_process.py +281 -0
- autocoder/common/shell_commands/tests/__init__.py +6 -0
- autocoder/common/shell_commands/tests/conftest.py +118 -0
- autocoder/common/shell_commands/tests/test_background_process_notifier.py +703 -0
- autocoder/common/shell_commands/tests/test_command_executor.py +448 -0
- autocoder/common/shell_commands/tests/test_error_recovery.py +305 -0
- autocoder/common/shell_commands/tests/test_exceptions.py +299 -0
- autocoder/common/shell_commands/tests/test_execute_batch.py +588 -0
- autocoder/common/shell_commands/tests/test_indented_batch_commands.py +244 -0
- autocoder/common/shell_commands/tests/test_integration.py +664 -0
- autocoder/common/shell_commands/tests/test_monitoring.py +546 -0
- autocoder/common/shell_commands/tests/test_performance.py +632 -0
- autocoder/common/shell_commands/tests/test_process_cleanup.py +397 -0
- autocoder/common/shell_commands/tests/test_process_manager.py +606 -0
- autocoder/common/shell_commands/tests/test_timeout_config.py +343 -0
- autocoder/common/shell_commands/tests/test_timeout_manager.py +520 -0
- autocoder/common/shell_commands/timeout_config.py +315 -0
- autocoder/common/shell_commands/timeout_manager.py +352 -0
- autocoder/common/terminal_paste/__init__.py +14 -0
- autocoder/common/terminal_paste/demo.py +145 -0
- autocoder/common/terminal_paste/demo_paste_functionality.py +95 -0
- autocoder/common/terminal_paste/paste_handler.py +200 -0
- autocoder/common/terminal_paste/paste_manager.py +118 -0
- autocoder/common/terminal_paste/tests/__init__.py +1 -0
- autocoder/common/terminal_paste/tests/test_paste_handler.py +182 -0
- autocoder/common/terminal_paste/tests/test_paste_manager.py +126 -0
- autocoder/common/terminal_paste/utils.py +163 -0
- autocoder/common/test_autocoder_args.py +232 -0
- autocoder/common/test_env_manager.py +173 -0
- autocoder/common/test_env_manager_integration.py +159 -0
- autocoder/common/text_similarity/__init__.py +9 -0
- autocoder/common/text_similarity/demo.py +216 -0
- autocoder/common/text_similarity/examples.py +266 -0
- autocoder/common/text_similarity/test_text_similarity.py +306 -0
- autocoder/common/text_similarity/text_similarity.py +194 -0
- autocoder/common/text_similarity/utils.py +125 -0
- autocoder/common/todos/__init__.py +61 -0
- autocoder/common/todos/cache/__init__.py +16 -0
- autocoder/common/todos/cache/base_cache.py +89 -0
- autocoder/common/todos/cache/cache_manager.py +228 -0
- autocoder/common/todos/cache/memory_cache.py +225 -0
- autocoder/common/todos/config.py +155 -0
- autocoder/common/todos/exceptions.py +35 -0
- autocoder/common/todos/get_todo_manager.py +161 -0
- autocoder/common/todos/manager.py +537 -0
- autocoder/common/todos/models.py +239 -0
- autocoder/common/todos/storage/__init__.py +14 -0
- autocoder/common/todos/storage/base_storage.py +76 -0
- autocoder/common/todos/storage/file_storage.py +278 -0
- autocoder/common/tokens/counter.py +24 -2
- autocoder/common/tools_manager/__init__.py +17 -0
- autocoder/common/tools_manager/examples.py +162 -0
- autocoder/common/tools_manager/manager.py +385 -0
- autocoder/common/tools_manager/models.py +39 -0
- autocoder/common/tools_manager/test_tools_manager.py +303 -0
- autocoder/common/tools_manager/utils.py +191 -0
- autocoder/common/v2/agent/agentic_callbacks.py +270 -0
- autocoder/common/v2/agent/agentic_edit.py +2699 -1856
- autocoder/common/v2/agent/agentic_edit_change_manager.py +474 -0
- autocoder/common/v2/agent/agentic_edit_tools/__init__.py +35 -1
- autocoder/common/v2/agent/agentic_edit_tools/ac_mod_list_tool_resolver.py +279 -0
- autocoder/common/v2/agent/agentic_edit_tools/ac_mod_write_tool_resolver.py +10 -1
- autocoder/common/v2/agent/agentic_edit_tools/background_task_tool_resolver.py +1167 -0
- autocoder/common/v2/agent/agentic_edit_tools/base_tool_resolver.py +2 -2
- autocoder/common/v2/agent/agentic_edit_tools/conversation_message_ids_read_tool_resolver.py +214 -0
- autocoder/common/v2/agent/agentic_edit_tools/conversation_message_ids_write_tool_resolver.py +299 -0
- autocoder/common/v2/agent/agentic_edit_tools/count_tokens_tool_resolver.py +290 -0
- autocoder/common/v2/agent/agentic_edit_tools/execute_command_tool_resolver.py +564 -29
- autocoder/common/v2/agent/agentic_edit_tools/execute_workflow_tool_resolver.py +485 -0
- autocoder/common/v2/agent/agentic_edit_tools/extract_to_text_tool_resolver.py +225 -0
- autocoder/common/v2/agent/agentic_edit_tools/lint_report.py +79 -0
- autocoder/common/v2/agent/agentic_edit_tools/linter_config_models.py +343 -0
- autocoder/common/v2/agent/agentic_edit_tools/linter_enabled_tool_resolver.py +189 -0
- autocoder/common/v2/agent/agentic_edit_tools/list_files_tool_resolver.py +169 -101
- autocoder/common/v2/agent/agentic_edit_tools/load_extra_document_tool_resolver.py +349 -0
- autocoder/common/v2/agent/agentic_edit_tools/read_file_tool_resolver.py +243 -50
- autocoder/common/v2/agent/agentic_edit_tools/replace_in_file_tool_resolver.py +667 -147
- autocoder/common/v2/agent/agentic_edit_tools/run_named_subagents_tool_resolver.py +691 -0
- autocoder/common/v2/agent/agentic_edit_tools/search_files_tool_resolver.py +410 -86
- autocoder/common/v2/agent/agentic_edit_tools/session_interactive_tool_resolver.py +115 -0
- autocoder/common/v2/agent/agentic_edit_tools/session_start_tool_resolver.py +190 -0
- autocoder/common/v2/agent/agentic_edit_tools/session_stop_tool_resolver.py +76 -0
- autocoder/common/v2/agent/agentic_edit_tools/test_write_to_file_tool_resolver.py +207 -192
- autocoder/common/v2/agent/agentic_edit_tools/todo_read_tool_resolver.py +80 -63
- autocoder/common/v2/agent/agentic_edit_tools/todo_write_tool_resolver.py +237 -233
- autocoder/common/v2/agent/agentic_edit_tools/use_mcp_tool_resolver.py +2 -2
- autocoder/common/v2/agent/agentic_edit_tools/web_crawl_tool_resolver.py +557 -0
- autocoder/common/v2/agent/agentic_edit_tools/web_search_tool_resolver.py +600 -0
- autocoder/common/v2/agent/agentic_edit_tools/write_to_file_tool_resolver.py +56 -121
- autocoder/common/v2/agent/agentic_edit_types.py +343 -9
- autocoder/common/v2/agent/runner/__init__.py +3 -3
- autocoder/common/v2/agent/runner/base_runner.py +12 -26
- autocoder/common/v2/agent/runner/{event_runner.py → file_based_event_runner.py} +3 -2
- autocoder/common/v2/agent/runner/sdk_runner.py +150 -8
- autocoder/common/v2/agent/runner/terminal_runner.py +170 -57
- autocoder/common/v2/agent/runner/tool_display.py +557 -159
- autocoder/common/v2/agent/test_agentic_callbacks.py +265 -0
- autocoder/common/v2/agent/test_agentic_edit.py +194 -0
- autocoder/common/v2/agent/tool_caller/__init__.py +24 -0
- autocoder/common/v2/agent/tool_caller/default_tool_resolver_map.py +135 -0
- autocoder/common/v2/agent/tool_caller/integration_test.py +172 -0
- autocoder/common/v2/agent/tool_caller/plugins/__init__.py +14 -0
- autocoder/common/v2/agent/tool_caller/plugins/base_plugin.py +126 -0
- autocoder/common/v2/agent/tool_caller/plugins/examples/__init__.py +13 -0
- autocoder/common/v2/agent/tool_caller/plugins/examples/logging_plugin.py +164 -0
- autocoder/common/v2/agent/tool_caller/plugins/examples/security_filter_plugin.py +198 -0
- autocoder/common/v2/agent/tool_caller/plugins/plugin_interface.py +141 -0
- autocoder/common/v2/agent/tool_caller/test_tool_caller.py +278 -0
- autocoder/common/v2/agent/tool_caller/tool_call_plugin_manager.py +331 -0
- autocoder/common/v2/agent/tool_caller/tool_caller.py +337 -0
- autocoder/common/v2/agent/tool_caller/usage_example.py +193 -0
- autocoder/common/v2/code_agentic_editblock_manager.py +4 -4
- autocoder/common/v2/code_auto_generate.py +136 -78
- autocoder/common/v2/code_auto_generate_diff.py +135 -79
- autocoder/common/v2/code_auto_generate_editblock.py +174 -99
- autocoder/common/v2/code_auto_generate_strict_diff.py +151 -71
- autocoder/common/v2/code_auto_merge.py +1 -1
- autocoder/common/v2/code_auto_merge_editblock.py +13 -1
- autocoder/common/v2/code_diff_manager.py +3 -3
- autocoder/common/v2/code_editblock_manager.py +4 -14
- autocoder/common/v2/code_manager.py +1 -1
- autocoder/common/v2/code_strict_diff_manager.py +2 -2
- autocoder/common/wrap_llm_hint/__init__.py +10 -0
- autocoder/common/wrap_llm_hint/test_wrap_llm_hint.py +1067 -0
- autocoder/common/wrap_llm_hint/utils.py +432 -0
- autocoder/common/wrap_llm_hint/wrap_llm_hint.py +323 -0
- autocoder/completer/__init__.py +8 -0
- autocoder/completer/command_completer_v2.py +1051 -0
- autocoder/default_project/__init__.py +501 -0
- autocoder/dispacher/__init__.py +4 -12
- autocoder/dispacher/actions/action.py +165 -7
- autocoder/dispacher/actions/plugins/action_regex_project.py +2 -2
- autocoder/index/entry.py +116 -124
- autocoder/{agent → index/filter}/agentic_filter.py +322 -333
- autocoder/index/filter/normal_filter.py +5 -11
- autocoder/index/filter/quick_filter.py +1 -1
- autocoder/index/index.py +36 -9
- autocoder/index/tests/__init__.py +1 -0
- autocoder/index/tests/run_tests.py +195 -0
- autocoder/index/tests/test_entry.py +303 -0
- autocoder/index/tests/test_index_manager.py +314 -0
- autocoder/index/tests/test_module_integration.py +300 -0
- autocoder/index/tests/test_symbols_utils.py +183 -0
- autocoder/inner/__init__.py +4 -0
- autocoder/inner/agentic.py +932 -0
- autocoder/inner/async_command_handler.py +992 -0
- autocoder/inner/conversation_command_handlers.py +623 -0
- autocoder/inner/merge_command_handler.py +213 -0
- autocoder/inner/queue_command_handler.py +684 -0
- autocoder/models.py +95 -266
- autocoder/plugins/git_helper_plugin.py +31 -29
- autocoder/plugins/token_helper_plugin.py +65 -46
- autocoder/pyproject/__init__.py +32 -29
- autocoder/rag/agentic_rag.py +215 -75
- autocoder/rag/cache/simple_cache.py +1 -2
- autocoder/rag/loaders/image_loader.py +1 -1
- autocoder/rag/long_context_rag.py +42 -26
- autocoder/rag/qa_conversation_strategy.py +1 -1
- autocoder/rag/terminal/__init__.py +17 -0
- autocoder/rag/terminal/args.py +581 -0
- autocoder/rag/terminal/bootstrap.py +61 -0
- autocoder/rag/terminal/command_handlers.py +653 -0
- autocoder/rag/terminal/formatters/__init__.py +20 -0
- autocoder/rag/terminal/formatters/base.py +70 -0
- autocoder/rag/terminal/formatters/json_format.py +66 -0
- autocoder/rag/terminal/formatters/stream_json.py +95 -0
- autocoder/rag/terminal/formatters/text.py +28 -0
- autocoder/rag/terminal/init.py +120 -0
- autocoder/rag/terminal/utils.py +106 -0
- autocoder/rag/test_agentic_rag.py +389 -0
- autocoder/rag/test_doc_filter.py +3 -3
- autocoder/rag/test_long_context_rag.py +1 -1
- autocoder/rag/test_token_limiter.py +517 -10
- autocoder/rag/token_counter.py +3 -0
- autocoder/rag/token_limiter.py +19 -15
- autocoder/rag/tools/__init__.py +26 -2
- autocoder/rag/tools/bochaai_example.py +343 -0
- autocoder/rag/tools/bochaai_sdk.py +541 -0
- autocoder/rag/tools/metaso_example.py +268 -0
- autocoder/rag/tools/metaso_sdk.py +417 -0
- autocoder/rag/tools/recall_tool.py +28 -7
- autocoder/rag/tools/run_integration_tests.py +204 -0
- autocoder/rag/tools/test_all_providers.py +318 -0
- autocoder/rag/tools/test_bochaai_integration.py +482 -0
- autocoder/rag/tools/test_final_integration.py +215 -0
- autocoder/rag/tools/test_metaso_integration.py +424 -0
- autocoder/rag/tools/test_metaso_real.py +171 -0
- autocoder/rag/tools/test_web_crawl_tool.py +639 -0
- autocoder/rag/tools/test_web_search_tool.py +509 -0
- autocoder/rag/tools/todo_read_tool.py +202 -0
- autocoder/rag/tools/todo_write_tool.py +412 -0
- autocoder/rag/tools/web_crawl_tool.py +634 -0
- autocoder/rag/tools/web_search_tool.py +558 -0
- autocoder/rag/tools/web_tools_example.py +119 -0
- autocoder/rag/types.py +16 -0
- autocoder/rag/variable_holder.py +4 -2
- autocoder/rags.py +86 -79
- autocoder/regexproject/__init__.py +23 -21
- autocoder/sdk/__init__.py +46 -190
- autocoder/sdk/api.py +370 -0
- autocoder/sdk/async_runner/__init__.py +26 -0
- autocoder/sdk/async_runner/async_executor.py +650 -0
- autocoder/sdk/async_runner/async_handler.py +356 -0
- autocoder/sdk/async_runner/markdown_processor.py +595 -0
- autocoder/sdk/async_runner/task_metadata.py +284 -0
- autocoder/sdk/async_runner/worktree_manager.py +438 -0
- autocoder/sdk/cli/__init__.py +2 -5
- autocoder/sdk/cli/formatters.py +28 -204
- autocoder/sdk/cli/handlers.py +77 -44
- autocoder/sdk/cli/main.py +154 -171
- autocoder/sdk/cli/options.py +95 -22
- autocoder/sdk/constants.py +139 -51
- autocoder/sdk/core/auto_coder_core.py +484 -109
- autocoder/sdk/core/bridge.py +297 -115
- autocoder/sdk/exceptions.py +18 -12
- autocoder/sdk/formatters/__init__.py +19 -0
- autocoder/sdk/formatters/input.py +64 -0
- autocoder/sdk/formatters/output.py +247 -0
- autocoder/sdk/formatters/stream.py +54 -0
- autocoder/sdk/models/__init__.py +6 -5
- autocoder/sdk/models/options.py +55 -18
- autocoder/sdk/utils/formatters.py +27 -195
- autocoder/suffixproject/__init__.py +28 -25
- autocoder/terminal/__init__.py +14 -0
- autocoder/terminal/app.py +454 -0
- autocoder/terminal/args.py +32 -0
- autocoder/terminal/bootstrap.py +178 -0
- autocoder/terminal/command_processor.py +521 -0
- autocoder/terminal/command_registry.py +57 -0
- autocoder/terminal/help.py +97 -0
- autocoder/terminal/tasks/__init__.py +5 -0
- autocoder/terminal/tasks/background.py +77 -0
- autocoder/terminal/tasks/task_event.py +70 -0
- autocoder/terminal/ui/__init__.py +13 -0
- autocoder/terminal/ui/completer.py +268 -0
- autocoder/terminal/ui/keybindings.py +75 -0
- autocoder/terminal/ui/session.py +41 -0
- autocoder/terminal/ui/toolbar.py +64 -0
- autocoder/terminal/utils/__init__.py +13 -0
- autocoder/terminal/utils/errors.py +18 -0
- autocoder/terminal/utils/paths.py +19 -0
- autocoder/terminal/utils/shell.py +43 -0
- autocoder/terminal_v3/__init__.py +10 -0
- autocoder/terminal_v3/app.py +201 -0
- autocoder/terminal_v3/handlers/__init__.py +5 -0
- autocoder/terminal_v3/handlers/command_handler.py +131 -0
- autocoder/terminal_v3/models/__init__.py +6 -0
- autocoder/terminal_v3/models/conversation_buffer.py +214 -0
- autocoder/terminal_v3/models/message.py +50 -0
- autocoder/terminal_v3/models/tool_display.py +247 -0
- autocoder/terminal_v3/ui/__init__.py +7 -0
- autocoder/terminal_v3/ui/keybindings.py +56 -0
- autocoder/terminal_v3/ui/layout.py +141 -0
- autocoder/terminal_v3/ui/styles.py +43 -0
- autocoder/tsproject/__init__.py +23 -23
- autocoder/utils/auto_coder_utils/chat_stream_out.py +1 -1
- autocoder/utils/llms.py +88 -80
- autocoder/utils/math_utils.py +101 -0
- autocoder/utils/model_provider_selector.py +16 -4
- autocoder/utils/operate_config_api.py +33 -5
- autocoder/utils/thread_utils.py +2 -2
- autocoder/version.py +4 -2
- autocoder/workflow_agents/__init__.py +84 -0
- autocoder/workflow_agents/agent.py +143 -0
- autocoder/workflow_agents/exceptions.py +573 -0
- autocoder/workflow_agents/executor.py +489 -0
- autocoder/workflow_agents/loader.py +737 -0
- autocoder/workflow_agents/runner.py +267 -0
- autocoder/workflow_agents/types.py +172 -0
- autocoder/workflow_agents/utils.py +434 -0
- autocoder/workflow_agents/workflow_manager.py +211 -0
- auto_coder-1.0.0.dist-info/METADATA +0 -396
- auto_coder-1.0.0.dist-info/RECORD +0 -442
- auto_coder-1.0.0.dist-info/licenses/LICENSE +0 -201
- autocoder/auto_coder_server.py +0 -672
- autocoder/benchmark.py +0 -138
- autocoder/common/ac_style_command_parser/example.py +0 -7
- autocoder/common/cleaner.py +0 -31
- autocoder/common/command_completer_v2.py +0 -615
- autocoder/common/context_pruner.py +0 -477
- autocoder/common/conversation_pruner.py +0 -132
- autocoder/common/directory_cache/__init__.py +0 -1
- autocoder/common/directory_cache/cache.py +0 -192
- autocoder/common/directory_cache/test_cache.py +0 -190
- autocoder/common/file_checkpoint/examples.py +0 -217
- autocoder/common/llm_friendly_package_example.py +0 -138
- autocoder/common/llm_friendly_package_test.py +0 -63
- autocoder/common/pull_requests/test_module.py +0 -1
- autocoder/common/rulefiles/autocoderrules_utils.py +0 -484
- autocoder/common/text.py +0 -30
- autocoder/common/v2/agent/agentic_edit_tools/list_package_info_tool_resolver.py +0 -42
- autocoder/common/v2/agent/agentic_edit_tools/test_execute_command_tool_resolver.py +0 -70
- autocoder/common/v2/agent/agentic_edit_tools/test_search_files_tool_resolver.py +0 -163
- autocoder/common/v2/agent/agentic_tool_display.py +0 -183
- autocoder/plugins/dynamic_completion_example.py +0 -148
- autocoder/plugins/sample_plugin.py +0 -160
- autocoder/sdk/cli/__main__.py +0 -26
- autocoder/sdk/cli/completion_wrapper.py +0 -38
- autocoder/sdk/cli/install_completion.py +0 -301
- autocoder/sdk/models/messages.py +0 -209
- autocoder/sdk/session/__init__.py +0 -32
- autocoder/sdk/session/session.py +0 -106
- autocoder/sdk/session/session_manager.py +0 -56
- {auto_coder-1.0.0.dist-info → auto_coder-2.0.0.dist-info}/top_level.txt +0 -0
- /autocoder/{sdk/example.py → common/agent_query_queue/__init__.py} +0 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Base cache interface for todo caching.
|
|
3
|
+
|
|
4
|
+
This module defines the abstract base class for all cache implementations,
|
|
5
|
+
providing a consistent interface for caching operations.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from abc import ABC, abstractmethod
|
|
9
|
+
from typing import Optional, Any, List
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class BaseCache(ABC):
|
|
13
|
+
"""Abstract base class for cache implementations."""
|
|
14
|
+
|
|
15
|
+
@abstractmethod
|
|
16
|
+
def get(self, key: str) -> Optional[Any]:
|
|
17
|
+
"""
|
|
18
|
+
Get a value from the cache.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
key: The cache key
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
The cached value or None if not found/expired
|
|
25
|
+
"""
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
@abstractmethod
|
|
29
|
+
def set(self, key: str, value: Any, ttl: Optional[float] = None) -> None:
|
|
30
|
+
"""
|
|
31
|
+
Set a value in the cache.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
key: The cache key
|
|
35
|
+
value: The value to cache
|
|
36
|
+
ttl: Time to live in seconds, None for no expiration
|
|
37
|
+
"""
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
@abstractmethod
|
|
41
|
+
def delete(self, key: str) -> bool:
|
|
42
|
+
"""
|
|
43
|
+
Delete a value from the cache.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
key: The cache key
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
True if the key was deleted, False if it didn't exist
|
|
50
|
+
"""
|
|
51
|
+
pass
|
|
52
|
+
|
|
53
|
+
@abstractmethod
|
|
54
|
+
def clear(self) -> None:
|
|
55
|
+
"""Clear all items from the cache."""
|
|
56
|
+
pass
|
|
57
|
+
|
|
58
|
+
@abstractmethod
|
|
59
|
+
def exists(self, key: str) -> bool:
|
|
60
|
+
"""
|
|
61
|
+
Check if a key exists in the cache.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
key: The cache key
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
True if the key exists and is not expired, False otherwise
|
|
68
|
+
"""
|
|
69
|
+
pass
|
|
70
|
+
|
|
71
|
+
@abstractmethod
|
|
72
|
+
def size(self) -> int:
|
|
73
|
+
"""
|
|
74
|
+
Get the current number of items in the cache.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
The number of items currently in the cache
|
|
78
|
+
"""
|
|
79
|
+
pass
|
|
80
|
+
|
|
81
|
+
@abstractmethod
|
|
82
|
+
def keys(self) -> List[str]:
|
|
83
|
+
"""
|
|
84
|
+
Get all keys currently in the cache.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
List of keys currently in the cache
|
|
88
|
+
"""
|
|
89
|
+
pass
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Cache manager for todo caching.
|
|
3
|
+
|
|
4
|
+
This module provides a high-level interface for managing caches of
|
|
5
|
+
todo lists, with support for cache warming, invalidation,
|
|
6
|
+
and statistics reporting.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
from typing import Optional, List, Dict, Any
|
|
11
|
+
|
|
12
|
+
from .base_cache import BaseCache
|
|
13
|
+
from .memory_cache import MemoryCache
|
|
14
|
+
from ..models import TodoList
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class CacheManager:
|
|
20
|
+
"""High-level cache manager for todo lists."""
|
|
21
|
+
|
|
22
|
+
def __init__(self, todo_cache: Optional[BaseCache] = None):
|
|
23
|
+
"""
|
|
24
|
+
Initialize cache manager.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
todo_cache: Cache instance for todo lists
|
|
28
|
+
"""
|
|
29
|
+
self.todo_cache = todo_cache or MemoryCache(
|
|
30
|
+
max_size=50, default_ttl=300.0 # 5 minutes default
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
# Ensure cache implements required interface
|
|
34
|
+
self._validate_cache_interface(self.todo_cache)
|
|
35
|
+
|
|
36
|
+
def _validate_cache_interface(self, cache: BaseCache) -> None:
|
|
37
|
+
"""Validate that cache implements required interface."""
|
|
38
|
+
required_methods = ['get', 'set', 'delete', 'clear', 'exists', 'size', 'keys']
|
|
39
|
+
for method in required_methods:
|
|
40
|
+
if not hasattr(cache, method) or not callable(getattr(cache, method)):
|
|
41
|
+
raise TypeError(f"Cache must implement {method} method")
|
|
42
|
+
|
|
43
|
+
def _get_todo_list_key(self, conversation_id: str) -> str:
|
|
44
|
+
"""Generate cache key for todo list."""
|
|
45
|
+
return f"todos:{conversation_id}"
|
|
46
|
+
|
|
47
|
+
def cache_todo_list(
|
|
48
|
+
self,
|
|
49
|
+
todo_list: Dict[str, Any],
|
|
50
|
+
ttl: Optional[float] = None
|
|
51
|
+
) -> None:
|
|
52
|
+
"""
|
|
53
|
+
Cache a todo list.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
todo_list: The todo list to cache
|
|
57
|
+
ttl: Time to live in seconds, None for default
|
|
58
|
+
"""
|
|
59
|
+
try:
|
|
60
|
+
conversation_id = todo_list.get('conversation_id')
|
|
61
|
+
if not conversation_id:
|
|
62
|
+
logger.error("Cannot cache todo list without conversation_id")
|
|
63
|
+
return
|
|
64
|
+
|
|
65
|
+
key = self._get_todo_list_key(conversation_id)
|
|
66
|
+
self.todo_cache.set(key, todo_list, ttl=ttl)
|
|
67
|
+
logger.debug(f"Cached todo list for conversation {conversation_id}")
|
|
68
|
+
except Exception as e:
|
|
69
|
+
logger.error(f"Failed to cache todo list for conversation {conversation_id}: {e}")
|
|
70
|
+
|
|
71
|
+
def get_todo_list(self, conversation_id: str) -> Optional[Dict[str, Any]]:
|
|
72
|
+
"""
|
|
73
|
+
Get a todo list from cache.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
conversation_id: The conversation ID
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
The cached todo list or None if not found
|
|
80
|
+
"""
|
|
81
|
+
try:
|
|
82
|
+
key = self._get_todo_list_key(conversation_id)
|
|
83
|
+
todo_list = self.todo_cache.get(key)
|
|
84
|
+
if todo_list:
|
|
85
|
+
logger.debug(f"Cache hit for todo list of conversation {conversation_id}")
|
|
86
|
+
else:
|
|
87
|
+
logger.debug(f"Cache miss for todo list of conversation {conversation_id}")
|
|
88
|
+
return todo_list
|
|
89
|
+
except Exception as e:
|
|
90
|
+
logger.error(f"Failed to get todo list for conversation {conversation_id} from cache: {e}")
|
|
91
|
+
return None
|
|
92
|
+
|
|
93
|
+
def invalidate_todo_list(self, conversation_id: str) -> bool:
|
|
94
|
+
"""
|
|
95
|
+
Invalidate cached todo list.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
conversation_id: The conversation ID
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
True if todo list was cached and removed, False otherwise
|
|
102
|
+
"""
|
|
103
|
+
try:
|
|
104
|
+
key = self._get_todo_list_key(conversation_id)
|
|
105
|
+
result = self.todo_cache.delete(key)
|
|
106
|
+
if result:
|
|
107
|
+
logger.debug(f"Invalidated todo list for conversation {conversation_id}")
|
|
108
|
+
return result
|
|
109
|
+
except Exception as e:
|
|
110
|
+
logger.error(f"Failed to invalidate todo list for conversation {conversation_id}: {e}")
|
|
111
|
+
return False
|
|
112
|
+
|
|
113
|
+
def cache_todo_lists(
|
|
114
|
+
self,
|
|
115
|
+
todo_lists: List[Dict[str, Any]],
|
|
116
|
+
ttl: Optional[float] = None
|
|
117
|
+
) -> int:
|
|
118
|
+
"""
|
|
119
|
+
Cache multiple todo lists.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
todo_lists: List of todo lists to cache
|
|
123
|
+
ttl: Time to live in seconds, None for default
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
Number of todo lists successfully cached
|
|
127
|
+
"""
|
|
128
|
+
count = 0
|
|
129
|
+
for todo_list in todo_lists:
|
|
130
|
+
try:
|
|
131
|
+
self.cache_todo_list(todo_list, ttl=ttl)
|
|
132
|
+
count += 1
|
|
133
|
+
except Exception as e:
|
|
134
|
+
conversation_id = todo_list.get('conversation_id', 'unknown')
|
|
135
|
+
logger.error(f"Failed to cache todo list for conversation {conversation_id}: {e}")
|
|
136
|
+
|
|
137
|
+
return count
|
|
138
|
+
|
|
139
|
+
def invalidate_todo_lists(self, conversation_ids: List[str]) -> Dict[str, bool]:
|
|
140
|
+
"""
|
|
141
|
+
Invalidate multiple todo lists.
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
conversation_ids: List of conversation IDs to invalidate
|
|
145
|
+
|
|
146
|
+
Returns:
|
|
147
|
+
Dictionary mapping conversation IDs to invalidation results
|
|
148
|
+
"""
|
|
149
|
+
results = {}
|
|
150
|
+
for conversation_id in conversation_ids:
|
|
151
|
+
results[conversation_id] = self.invalidate_todo_list(conversation_id)
|
|
152
|
+
|
|
153
|
+
return results
|
|
154
|
+
|
|
155
|
+
def clear_all_caches(self) -> None:
|
|
156
|
+
"""Clear all caches."""
|
|
157
|
+
try:
|
|
158
|
+
self.todo_cache.clear()
|
|
159
|
+
logger.info("Cleared all todo caches")
|
|
160
|
+
except Exception as e:
|
|
161
|
+
logger.error(f"Failed to clear caches: {e}")
|
|
162
|
+
|
|
163
|
+
def get_cache_statistics(self) -> Dict[str, Any]:
|
|
164
|
+
"""
|
|
165
|
+
Get statistics for all caches.
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
Dictionary with cache statistics
|
|
169
|
+
"""
|
|
170
|
+
try:
|
|
171
|
+
stats = {
|
|
172
|
+
"todo_cache": {
|
|
173
|
+
"size": self.todo_cache.size(),
|
|
174
|
+
"max_size": getattr(self.todo_cache, 'max_size', 'unknown')
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
# Add detailed stats if available
|
|
179
|
+
if hasattr(self.todo_cache, 'get_statistics'):
|
|
180
|
+
get_stats_method = getattr(self.todo_cache, 'get_statistics')
|
|
181
|
+
stats["todo_cache"].update(
|
|
182
|
+
get_stats_method()
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
return stats
|
|
186
|
+
|
|
187
|
+
except Exception as e:
|
|
188
|
+
logger.error(f"Failed to get cache statistics: {e}")
|
|
189
|
+
return {
|
|
190
|
+
"todo_cache": {"size": 0, "max_size": "unknown"},
|
|
191
|
+
"error": str(e)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
def is_todo_list_cached(self, conversation_id: str) -> bool:
|
|
195
|
+
"""
|
|
196
|
+
Check if a todo list is cached.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
conversation_id: The conversation ID
|
|
200
|
+
|
|
201
|
+
Returns:
|
|
202
|
+
True if todo list is cached, False otherwise
|
|
203
|
+
"""
|
|
204
|
+
try:
|
|
205
|
+
key = self._get_todo_list_key(conversation_id)
|
|
206
|
+
return self.todo_cache.exists(key)
|
|
207
|
+
except Exception as e:
|
|
208
|
+
logger.error(f"Failed to check if todo list for conversation {conversation_id} is cached: {e}")
|
|
209
|
+
return False
|
|
210
|
+
|
|
211
|
+
def get_cached_conversation_ids(self) -> List[str]:
|
|
212
|
+
"""
|
|
213
|
+
Get all cached conversation IDs.
|
|
214
|
+
|
|
215
|
+
Returns:
|
|
216
|
+
List of conversation IDs currently cached
|
|
217
|
+
"""
|
|
218
|
+
try:
|
|
219
|
+
keys = self.todo_cache.keys()
|
|
220
|
+
# Extract conversation IDs from cache keys
|
|
221
|
+
conversation_ids = []
|
|
222
|
+
for key in keys:
|
|
223
|
+
if key.startswith("todos:"):
|
|
224
|
+
conversation_ids.append(key[6:]) # Remove "todos:" prefix
|
|
225
|
+
return conversation_ids
|
|
226
|
+
except Exception as e:
|
|
227
|
+
logger.error(f"Failed to get cached conversation IDs: {e}")
|
|
228
|
+
return []
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Memory-based cache implementation with LRU eviction and TTL support.
|
|
3
|
+
|
|
4
|
+
This module provides a thread-safe in-memory cache with configurable
|
|
5
|
+
size limits, TTL expiration, and LRU eviction policies.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import time
|
|
9
|
+
import threading
|
|
10
|
+
from collections import OrderedDict
|
|
11
|
+
from typing import Optional, Any, List, Dict
|
|
12
|
+
from dataclasses import dataclass
|
|
13
|
+
|
|
14
|
+
from .base_cache import BaseCache
|
|
15
|
+
|
|
16
|
+
# Sentinel object to distinguish between "no ttl provided" and "ttl=None"
|
|
17
|
+
_TTL_NOT_PROVIDED = object()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class CacheEntry:
|
|
22
|
+
"""Cache entry with value and expiration time."""
|
|
23
|
+
value: Any
|
|
24
|
+
expires_at: Optional[float] = None
|
|
25
|
+
|
|
26
|
+
def is_expired(self) -> bool:
|
|
27
|
+
"""Check if this entry has expired."""
|
|
28
|
+
if self.expires_at is None:
|
|
29
|
+
return False
|
|
30
|
+
return time.time() > self.expires_at
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class MemoryCache(BaseCache):
|
|
34
|
+
"""Thread-safe in-memory cache with LRU eviction and TTL support."""
|
|
35
|
+
|
|
36
|
+
def __init__(self, max_size: int = 50, default_ttl: float = 300.0):
|
|
37
|
+
"""
|
|
38
|
+
Initialize memory cache.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
max_size: Maximum number of items to cache
|
|
42
|
+
default_ttl: Default TTL in seconds for cached items
|
|
43
|
+
"""
|
|
44
|
+
if max_size <= 0:
|
|
45
|
+
raise ValueError("max_size must be positive")
|
|
46
|
+
|
|
47
|
+
self.max_size = max_size
|
|
48
|
+
self.default_ttl = default_ttl
|
|
49
|
+
self._cache: OrderedDict[str, CacheEntry] = OrderedDict()
|
|
50
|
+
self._lock = threading.RLock()
|
|
51
|
+
|
|
52
|
+
# Optional statistics
|
|
53
|
+
self.hit_count = 0
|
|
54
|
+
self.miss_count = 0
|
|
55
|
+
|
|
56
|
+
def get(self, key: str) -> Optional[Any]:
|
|
57
|
+
"""
|
|
58
|
+
Get a value from the cache.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
key: The cache key
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
The cached value or None if not found/expired
|
|
65
|
+
"""
|
|
66
|
+
with self._lock:
|
|
67
|
+
entry = self._cache.get(key)
|
|
68
|
+
|
|
69
|
+
if entry is None:
|
|
70
|
+
self.miss_count += 1
|
|
71
|
+
return None
|
|
72
|
+
|
|
73
|
+
if entry.is_expired():
|
|
74
|
+
# Remove expired entry
|
|
75
|
+
del self._cache[key]
|
|
76
|
+
self.miss_count += 1
|
|
77
|
+
return None
|
|
78
|
+
|
|
79
|
+
# Move to end (most recently used)
|
|
80
|
+
self._cache.move_to_end(key)
|
|
81
|
+
self.hit_count += 1
|
|
82
|
+
return entry.value
|
|
83
|
+
|
|
84
|
+
def set(self, key: str, value: Any, ttl = _TTL_NOT_PROVIDED) -> None:
|
|
85
|
+
"""
|
|
86
|
+
Set a value in the cache.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
key: The cache key
|
|
90
|
+
value: The value to cache
|
|
91
|
+
ttl: Time to live in seconds, None for no expiration
|
|
92
|
+
"""
|
|
93
|
+
with self._lock:
|
|
94
|
+
# Calculate expiration time
|
|
95
|
+
expires_at = None
|
|
96
|
+
|
|
97
|
+
if ttl is _TTL_NOT_PROVIDED:
|
|
98
|
+
# No ttl provided, use default_ttl behavior
|
|
99
|
+
if self.default_ttl > 0:
|
|
100
|
+
expires_at = time.time() + self.default_ttl
|
|
101
|
+
elif ttl is None:
|
|
102
|
+
# Explicit None means permanent caching
|
|
103
|
+
expires_at = None
|
|
104
|
+
elif ttl > 0:
|
|
105
|
+
# Positive ttl value
|
|
106
|
+
expires_at = time.time() + ttl
|
|
107
|
+
# ttl <= 0 means permanent caching (expires_at stays None)
|
|
108
|
+
|
|
109
|
+
# Create cache entry
|
|
110
|
+
entry = CacheEntry(value=value, expires_at=expires_at)
|
|
111
|
+
|
|
112
|
+
# If key already exists, update it
|
|
113
|
+
if key in self._cache:
|
|
114
|
+
self._cache[key] = entry
|
|
115
|
+
self._cache.move_to_end(key)
|
|
116
|
+
else:
|
|
117
|
+
# Add new entry
|
|
118
|
+
self._cache[key] = entry
|
|
119
|
+
|
|
120
|
+
# Evict oldest items if over capacity
|
|
121
|
+
while len(self._cache) > self.max_size:
|
|
122
|
+
oldest_key = next(iter(self._cache))
|
|
123
|
+
del self._cache[oldest_key]
|
|
124
|
+
|
|
125
|
+
def delete(self, key: str) -> bool:
|
|
126
|
+
"""
|
|
127
|
+
Delete a value from the cache.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
key: The cache key
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
True if the key was deleted, False if it didn't exist
|
|
134
|
+
"""
|
|
135
|
+
with self._lock:
|
|
136
|
+
if key in self._cache:
|
|
137
|
+
del self._cache[key]
|
|
138
|
+
return True
|
|
139
|
+
return False
|
|
140
|
+
|
|
141
|
+
def clear(self) -> None:
|
|
142
|
+
"""Clear all items from the cache."""
|
|
143
|
+
with self._lock:
|
|
144
|
+
self._cache.clear()
|
|
145
|
+
|
|
146
|
+
def exists(self, key: str) -> bool:
|
|
147
|
+
"""
|
|
148
|
+
Check if a key exists in the cache.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
key: The cache key
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
True if the key exists and is not expired, False otherwise
|
|
155
|
+
"""
|
|
156
|
+
with self._lock:
|
|
157
|
+
entry = self._cache.get(key)
|
|
158
|
+
|
|
159
|
+
if entry is None:
|
|
160
|
+
return False
|
|
161
|
+
|
|
162
|
+
if entry.is_expired():
|
|
163
|
+
# Remove expired entry
|
|
164
|
+
del self._cache[key]
|
|
165
|
+
return False
|
|
166
|
+
|
|
167
|
+
return True
|
|
168
|
+
|
|
169
|
+
def size(self) -> int:
|
|
170
|
+
"""
|
|
171
|
+
Get the current number of items in the cache.
|
|
172
|
+
|
|
173
|
+
Returns:
|
|
174
|
+
The number of items currently in the cache
|
|
175
|
+
"""
|
|
176
|
+
with self._lock:
|
|
177
|
+
# Clean up expired items
|
|
178
|
+
self._cleanup_expired()
|
|
179
|
+
return len(self._cache)
|
|
180
|
+
|
|
181
|
+
def keys(self) -> List[str]:
|
|
182
|
+
"""
|
|
183
|
+
Get all keys currently in the cache.
|
|
184
|
+
|
|
185
|
+
Returns:
|
|
186
|
+
List of keys currently in the cache
|
|
187
|
+
"""
|
|
188
|
+
with self._lock:
|
|
189
|
+
# Clean up expired items
|
|
190
|
+
self._cleanup_expired()
|
|
191
|
+
return list(self._cache.keys())
|
|
192
|
+
|
|
193
|
+
def _cleanup_expired(self) -> None:
|
|
194
|
+
"""Remove all expired entries from the cache."""
|
|
195
|
+
current_time = time.time()
|
|
196
|
+
expired_keys = []
|
|
197
|
+
|
|
198
|
+
for key, entry in self._cache.items():
|
|
199
|
+
if entry.expires_at is not None and current_time > entry.expires_at:
|
|
200
|
+
expired_keys.append(key)
|
|
201
|
+
|
|
202
|
+
for key in expired_keys:
|
|
203
|
+
del self._cache[key]
|
|
204
|
+
|
|
205
|
+
def get_statistics(self) -> Dict[str, Any]:
|
|
206
|
+
"""
|
|
207
|
+
Get cache statistics.
|
|
208
|
+
|
|
209
|
+
Returns:
|
|
210
|
+
Dictionary with cache statistics
|
|
211
|
+
"""
|
|
212
|
+
with self._lock:
|
|
213
|
+
self._cleanup_expired()
|
|
214
|
+
|
|
215
|
+
total_requests = self.hit_count + self.miss_count
|
|
216
|
+
hit_rate = self.hit_count / total_requests if total_requests > 0 else 0.0
|
|
217
|
+
|
|
218
|
+
return {
|
|
219
|
+
"size": len(self._cache),
|
|
220
|
+
"max_size": self.max_size,
|
|
221
|
+
"hit_count": self.hit_count,
|
|
222
|
+
"miss_count": self.miss_count,
|
|
223
|
+
"hit_rate": hit_rate,
|
|
224
|
+
"default_ttl": self.default_ttl
|
|
225
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Todo manager configuration class.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import json
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from typing import Optional, Dict, Any
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class TodoManagerConfig:
|
|
13
|
+
"""Configuration class for todo manager"""
|
|
14
|
+
|
|
15
|
+
storage_path: str = "./.auto-coder/todos"
|
|
16
|
+
max_cache_size: int = 50
|
|
17
|
+
cache_ttl: float = 300.0
|
|
18
|
+
enable_compression: bool = False
|
|
19
|
+
log_level: str = "INFO"
|
|
20
|
+
|
|
21
|
+
def __post_init__(self):
|
|
22
|
+
"""Validate configuration"""
|
|
23
|
+
self._validate()
|
|
24
|
+
|
|
25
|
+
def _validate(self):
|
|
26
|
+
"""Validate configuration data"""
|
|
27
|
+
# Validate storage path
|
|
28
|
+
if not self.storage_path or not isinstance(self.storage_path, str):
|
|
29
|
+
raise ValueError("Storage path cannot be empty")
|
|
30
|
+
|
|
31
|
+
# Validate cache size
|
|
32
|
+
if not isinstance(self.max_cache_size, int) or self.max_cache_size <= 0:
|
|
33
|
+
raise ValueError("Cache size must be a positive integer")
|
|
34
|
+
|
|
35
|
+
# Validate cache TTL
|
|
36
|
+
if not isinstance(self.cache_ttl, (int, float)) or self.cache_ttl <= 0:
|
|
37
|
+
raise ValueError("Cache TTL must be a positive number")
|
|
38
|
+
|
|
39
|
+
# Validate log level
|
|
40
|
+
valid_levels = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
|
|
41
|
+
if self.log_level not in valid_levels:
|
|
42
|
+
raise ValueError(f"Invalid log level: {self.log_level}, valid levels: {valid_levels}")
|
|
43
|
+
|
|
44
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
45
|
+
"""Convert to dictionary"""
|
|
46
|
+
return {
|
|
47
|
+
"storage_path": self.storage_path,
|
|
48
|
+
"max_cache_size": self.max_cache_size,
|
|
49
|
+
"cache_ttl": self.cache_ttl,
|
|
50
|
+
"enable_compression": self.enable_compression,
|
|
51
|
+
"log_level": self.log_level
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@classmethod
|
|
55
|
+
def from_dict(cls, data: Dict[str, Any]) -> "TodoManagerConfig":
|
|
56
|
+
"""Create config from dictionary"""
|
|
57
|
+
config = cls()
|
|
58
|
+
|
|
59
|
+
for key, value in data.items():
|
|
60
|
+
if hasattr(config, key):
|
|
61
|
+
setattr(config, key, value)
|
|
62
|
+
|
|
63
|
+
config._validate()
|
|
64
|
+
return config
|
|
65
|
+
|
|
66
|
+
@classmethod
|
|
67
|
+
def from_env(cls, prefix: str = "TODO_") -> "TodoManagerConfig":
|
|
68
|
+
"""Create config from environment variables"""
|
|
69
|
+
config = cls()
|
|
70
|
+
|
|
71
|
+
env_mapping = {
|
|
72
|
+
f"{prefix}STORAGE_PATH": "storage_path",
|
|
73
|
+
f"{prefix}MAX_CACHE_SIZE": "max_cache_size",
|
|
74
|
+
f"{prefix}CACHE_TTL": "cache_ttl",
|
|
75
|
+
f"{prefix}ENABLE_COMPRESSION": "enable_compression",
|
|
76
|
+
f"{prefix}LOG_LEVEL": "log_level"
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
for env_key, attr_name in env_mapping.items():
|
|
80
|
+
env_value = os.environ.get(env_key)
|
|
81
|
+
if env_value is not None:
|
|
82
|
+
try:
|
|
83
|
+
if attr_name in ["max_cache_size"]:
|
|
84
|
+
value = int(env_value)
|
|
85
|
+
elif attr_name in ["cache_ttl"]:
|
|
86
|
+
value = float(env_value)
|
|
87
|
+
elif attr_name in ["enable_compression"]:
|
|
88
|
+
value = env_value.lower() in ["true", "1", "yes", "on"]
|
|
89
|
+
else:
|
|
90
|
+
value = env_value
|
|
91
|
+
|
|
92
|
+
setattr(config, attr_name, value)
|
|
93
|
+
except (ValueError, TypeError) as e:
|
|
94
|
+
raise ValueError(f"Environment variable {env_key} has invalid value '{env_value}': {e}")
|
|
95
|
+
|
|
96
|
+
config._validate()
|
|
97
|
+
return config
|
|
98
|
+
|
|
99
|
+
def save_to_file(self, file_path: str):
|
|
100
|
+
"""Save config to file"""
|
|
101
|
+
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
|
102
|
+
|
|
103
|
+
with open(file_path, 'w', encoding='utf-8') as f:
|
|
104
|
+
json.dump(self.to_dict(), f, indent=2, ensure_ascii=False)
|
|
105
|
+
|
|
106
|
+
@classmethod
|
|
107
|
+
def load_from_file(cls, file_path: str) -> "TodoManagerConfig":
|
|
108
|
+
"""Load config from file"""
|
|
109
|
+
if not os.path.exists(file_path):
|
|
110
|
+
raise FileNotFoundError(f"Config file not found: {file_path}")
|
|
111
|
+
|
|
112
|
+
try:
|
|
113
|
+
with open(file_path, 'r', encoding='utf-8') as f:
|
|
114
|
+
data = json.load(f)
|
|
115
|
+
|
|
116
|
+
return cls.from_dict(data)
|
|
117
|
+
except json.JSONDecodeError as e:
|
|
118
|
+
raise ValueError(f"Config file format error: {e}")
|
|
119
|
+
|
|
120
|
+
def copy(self) -> "TodoManagerConfig":
|
|
121
|
+
"""Create a deep copy of the config"""
|
|
122
|
+
return TodoManagerConfig.from_dict(self.to_dict())
|
|
123
|
+
|
|
124
|
+
def update(self, **kwargs):
|
|
125
|
+
"""Update config fields"""
|
|
126
|
+
backup_values = {}
|
|
127
|
+
for key in kwargs.keys():
|
|
128
|
+
if hasattr(self, key):
|
|
129
|
+
backup_values[key] = getattr(self, key)
|
|
130
|
+
else:
|
|
131
|
+
raise AttributeError(f"Config has no attribute: {key}")
|
|
132
|
+
|
|
133
|
+
try:
|
|
134
|
+
for key, value in kwargs.items():
|
|
135
|
+
setattr(self, key, value)
|
|
136
|
+
self._validate()
|
|
137
|
+
except Exception:
|
|
138
|
+
for key, value in backup_values.items():
|
|
139
|
+
setattr(self, key, value)
|
|
140
|
+
raise
|
|
141
|
+
|
|
142
|
+
def __repr__(self) -> str:
|
|
143
|
+
"""String representation"""
|
|
144
|
+
return (f"TodoManagerConfig("
|
|
145
|
+
f"storage_path='{self.storage_path}', "
|
|
146
|
+
f"max_cache_size={self.max_cache_size}, "
|
|
147
|
+
f"cache_ttl={self.cache_ttl}, "
|
|
148
|
+
f"log_level='{self.log_level}')")
|
|
149
|
+
|
|
150
|
+
def __eq__(self, other) -> bool:
|
|
151
|
+
"""Equality comparison"""
|
|
152
|
+
if not isinstance(other, TodoManagerConfig):
|
|
153
|
+
return False
|
|
154
|
+
|
|
155
|
+
return self.to_dict() == other.to_dict()
|