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.

Files changed (579) hide show
  1. auto_coder-2.0.0.dist-info/LICENSE +158 -0
  2. auto_coder-2.0.0.dist-info/METADATA +558 -0
  3. auto_coder-2.0.0.dist-info/RECORD +795 -0
  4. {auto_coder-0.1.400.dist-info → auto_coder-2.0.0.dist-info}/WHEEL +1 -1
  5. {auto_coder-0.1.400.dist-info → auto_coder-2.0.0.dist-info}/entry_points.txt +3 -3
  6. autocoder/__init__.py +31 -0
  7. autocoder/agent/auto_filegroup.py +32 -13
  8. autocoder/agent/auto_learn_from_commit.py +9 -1
  9. autocoder/agent/base_agentic/__init__.py +3 -0
  10. autocoder/agent/base_agentic/agent_hub.py +1 -1
  11. autocoder/agent/base_agentic/base_agent.py +235 -136
  12. autocoder/agent/base_agentic/default_tools.py +119 -118
  13. autocoder/agent/base_agentic/test_base_agent.py +1 -1
  14. autocoder/agent/base_agentic/tool_registry.py +32 -20
  15. autocoder/agent/base_agentic/tools/read_file_tool_resolver.py +25 -4
  16. autocoder/agent/base_agentic/tools/write_to_file_tool_resolver.py +24 -11
  17. autocoder/agent/base_agentic/types.py +42 -0
  18. autocoder/agent/entry_command_agent/chat.py +73 -59
  19. autocoder/auto_coder.py +31 -40
  20. autocoder/auto_coder_rag.py +11 -1084
  21. autocoder/auto_coder_runner.py +1029 -2310
  22. autocoder/auto_coder_terminal.py +26 -0
  23. autocoder/auto_coder_terminal_v3.py +190 -0
  24. autocoder/chat/conf_command.py +224 -124
  25. autocoder/chat/models_command.py +361 -299
  26. autocoder/chat/rules_command.py +79 -31
  27. autocoder/chat_auto_coder.py +1021 -372
  28. autocoder/chat_auto_coder_lang.py +23 -732
  29. autocoder/commands/auto_command.py +26 -9
  30. autocoder/commands/auto_web.py +1 -1
  31. autocoder/commands/tools.py +44 -44
  32. autocoder/common/__init__.py +150 -128
  33. autocoder/common/ac_style_command_parser/__init__.py +39 -2
  34. autocoder/common/ac_style_command_parser/config.py +422 -0
  35. autocoder/common/ac_style_command_parser/parser.py +292 -78
  36. autocoder/common/ac_style_command_parser/test_parser.py +241 -16
  37. autocoder/common/ac_style_command_parser/test_typed_parser.py +342 -0
  38. autocoder/common/ac_style_command_parser/typed_parser.py +653 -0
  39. autocoder/common/action_yml_file_manager.py +25 -13
  40. autocoder/common/agent_events/__init__.py +52 -0
  41. autocoder/common/agent_events/agent_event_emitter.py +193 -0
  42. autocoder/common/agent_events/event_factory.py +177 -0
  43. autocoder/common/agent_events/examples.py +307 -0
  44. autocoder/common/agent_events/types.py +113 -0
  45. autocoder/common/agent_events/utils.py +68 -0
  46. autocoder/common/agent_hooks/__init__.py +44 -0
  47. autocoder/common/agent_hooks/examples.py +582 -0
  48. autocoder/common/agent_hooks/hook_executor.py +217 -0
  49. autocoder/common/agent_hooks/hook_manager.py +288 -0
  50. autocoder/common/agent_hooks/types.py +133 -0
  51. autocoder/common/agent_hooks/utils.py +99 -0
  52. autocoder/common/agent_query_queue/queue_executor.py +324 -0
  53. autocoder/common/agent_query_queue/queue_manager.py +325 -0
  54. autocoder/common/agents/__init__.py +11 -0
  55. autocoder/common/agents/agent_manager.py +323 -0
  56. autocoder/common/agents/agent_parser.py +189 -0
  57. autocoder/common/agents/example_usage.py +344 -0
  58. autocoder/common/agents/integration_example.py +330 -0
  59. autocoder/common/agents/test_agent_parser.py +545 -0
  60. autocoder/common/async_utils.py +101 -0
  61. autocoder/common/auto_coder_lang.py +23 -972
  62. autocoder/common/autocoderargs_parser/__init__.py +14 -0
  63. autocoder/common/autocoderargs_parser/parser.py +184 -0
  64. autocoder/common/autocoderargs_parser/tests/__init__.py +1 -0
  65. autocoder/common/autocoderargs_parser/tests/test_args_parser.py +235 -0
  66. autocoder/common/autocoderargs_parser/tests/test_token_parser.py +195 -0
  67. autocoder/common/autocoderargs_parser/token_parser.py +290 -0
  68. autocoder/common/buildin_tokenizer.py +2 -4
  69. autocoder/common/code_auto_generate.py +149 -74
  70. autocoder/common/code_auto_generate_diff.py +163 -70
  71. autocoder/common/code_auto_generate_editblock.py +179 -89
  72. autocoder/common/code_auto_generate_strict_diff.py +167 -72
  73. autocoder/common/code_auto_merge_editblock.py +13 -6
  74. autocoder/common/code_modification_ranker.py +1 -1
  75. autocoder/common/command_completer.py +3 -3
  76. autocoder/common/command_file_manager/manager.py +183 -47
  77. autocoder/common/command_file_manager/test_command_file_manager.py +507 -0
  78. autocoder/common/command_templates.py +1 -1
  79. autocoder/common/conf_utils.py +2 -4
  80. autocoder/common/conversations/config.py +11 -3
  81. autocoder/common/conversations/get_conversation_manager.py +100 -2
  82. autocoder/common/conversations/llm_stats_models.py +264 -0
  83. autocoder/common/conversations/manager.py +112 -28
  84. autocoder/common/conversations/models.py +16 -2
  85. autocoder/common/conversations/storage/index_manager.py +134 -10
  86. autocoder/common/core_config/__init__.py +63 -0
  87. autocoder/common/core_config/agentic_mode_manager.py +109 -0
  88. autocoder/common/core_config/base_manager.py +123 -0
  89. autocoder/common/core_config/compatibility.py +151 -0
  90. autocoder/common/core_config/config_manager.py +156 -0
  91. autocoder/common/core_config/conversation_manager.py +31 -0
  92. autocoder/common/core_config/exclude_manager.py +72 -0
  93. autocoder/common/core_config/file_manager.py +177 -0
  94. autocoder/common/core_config/human_as_model_manager.py +129 -0
  95. autocoder/common/core_config/lib_manager.py +54 -0
  96. autocoder/common/core_config/main_manager.py +81 -0
  97. autocoder/common/core_config/mode_manager.py +126 -0
  98. autocoder/common/core_config/models.py +70 -0
  99. autocoder/common/core_config/test_memory_manager.py +1056 -0
  100. autocoder/common/env_manager.py +282 -0
  101. autocoder/common/env_manager_usage_example.py +211 -0
  102. autocoder/common/file_checkpoint/conversation_checkpoint.py +19 -19
  103. autocoder/common/file_checkpoint/manager.py +264 -48
  104. autocoder/common/file_checkpoint/test_backup.py +1 -18
  105. autocoder/common/file_checkpoint/test_manager.py +270 -1
  106. autocoder/common/file_checkpoint/test_store.py +1 -17
  107. autocoder/common/file_handler/__init__.py +23 -0
  108. autocoder/common/file_handler/active_context_handler.py +159 -0
  109. autocoder/common/file_handler/add_files_handler.py +409 -0
  110. autocoder/common/file_handler/chat_handler.py +180 -0
  111. autocoder/common/file_handler/coding_handler.py +401 -0
  112. autocoder/common/file_handler/commit_handler.py +200 -0
  113. autocoder/common/file_handler/lib_handler.py +156 -0
  114. autocoder/common/file_handler/list_files_handler.py +111 -0
  115. autocoder/common/file_handler/mcp_handler.py +268 -0
  116. autocoder/common/file_handler/models_handler.py +493 -0
  117. autocoder/common/file_handler/remove_files_handler.py +172 -0
  118. autocoder/common/file_monitor/test_file_monitor.py +307 -0
  119. autocoder/common/git_utils.py +51 -10
  120. autocoder/common/global_cancel.py +15 -6
  121. autocoder/common/ignorefiles/test_ignore_file_utils.py +1 -1
  122. autocoder/common/international/__init__.py +31 -0
  123. autocoder/common/international/demo_international.py +92 -0
  124. autocoder/common/international/message_manager.py +157 -0
  125. autocoder/common/international/messages/__init__.py +56 -0
  126. autocoder/common/international/messages/async_command_messages.py +507 -0
  127. autocoder/common/international/messages/auto_coder_messages.py +2208 -0
  128. autocoder/common/international/messages/chat_auto_coder_messages.py +1547 -0
  129. autocoder/common/international/messages/command_help_messages.py +986 -0
  130. autocoder/common/international/messages/conversation_command_messages.py +191 -0
  131. autocoder/common/international/messages/git_helper_plugin_messages.py +159 -0
  132. autocoder/common/international/messages/queue_command_messages.py +751 -0
  133. autocoder/common/international/messages/rules_command_messages.py +77 -0
  134. autocoder/common/international/messages/sdk_messages.py +1707 -0
  135. autocoder/common/international/messages/token_helper_plugin_messages.py +361 -0
  136. autocoder/common/international/messages/tool_display_messages.py +1212 -0
  137. autocoder/common/international/messages/workflow_exception_messages.py +473 -0
  138. autocoder/common/international/test_international.py +612 -0
  139. autocoder/common/linter_core/__init__.py +28 -0
  140. autocoder/common/linter_core/base_linter.py +61 -0
  141. autocoder/common/linter_core/config_loader.py +271 -0
  142. autocoder/common/linter_core/formatters/__init__.py +0 -0
  143. autocoder/common/linter_core/formatters/base_formatter.py +38 -0
  144. autocoder/common/linter_core/formatters/raw_formatter.py +17 -0
  145. autocoder/common/linter_core/linter.py +166 -0
  146. autocoder/common/linter_core/linter_factory.py +216 -0
  147. autocoder/common/linter_core/linter_manager.py +333 -0
  148. autocoder/common/linter_core/linters/__init__.py +9 -0
  149. autocoder/common/linter_core/linters/java_linter.py +342 -0
  150. autocoder/common/linter_core/linters/python_linter.py +115 -0
  151. autocoder/common/linter_core/linters/typescript_linter.py +119 -0
  152. autocoder/common/linter_core/models/__init__.py +7 -0
  153. autocoder/common/linter_core/models/lint_result.py +91 -0
  154. autocoder/common/linter_core/models.py +33 -0
  155. autocoder/common/linter_core/tests/__init__.py +3 -0
  156. autocoder/common/linter_core/tests/test_config_loader.py +323 -0
  157. autocoder/common/linter_core/tests/test_config_loading.py +308 -0
  158. autocoder/common/linter_core/tests/test_factory_manager.py +234 -0
  159. autocoder/common/linter_core/tests/test_formatters.py +147 -0
  160. autocoder/common/linter_core/tests/test_integration.py +317 -0
  161. autocoder/common/linter_core/tests/test_java_linter.py +496 -0
  162. autocoder/common/linter_core/tests/test_linters.py +265 -0
  163. autocoder/common/linter_core/tests/test_models.py +81 -0
  164. autocoder/common/linter_core/tests/verify_config_loading.py +296 -0
  165. autocoder/common/linter_core/tests/verify_fixes.py +183 -0
  166. autocoder/common/llm_friendly_package/__init__.py +31 -0
  167. autocoder/common/llm_friendly_package/base_manager.py +102 -0
  168. autocoder/common/llm_friendly_package/docs_manager.py +121 -0
  169. autocoder/common/llm_friendly_package/library_manager.py +171 -0
  170. autocoder/common/{llm_friendly_package.py → llm_friendly_package/main_manager.py} +204 -231
  171. autocoder/common/llm_friendly_package/models.py +40 -0
  172. autocoder/common/llm_friendly_package/test_llm_friendly_package.py +536 -0
  173. autocoder/common/llms/__init__.py +15 -0
  174. autocoder/common/llms/demo_error_handling.py +85 -0
  175. autocoder/common/llms/factory.py +142 -0
  176. autocoder/common/llms/manager.py +264 -0
  177. autocoder/common/llms/pricing.py +121 -0
  178. autocoder/common/llms/registry.py +288 -0
  179. autocoder/common/llms/schema.py +77 -0
  180. autocoder/common/llms/simple_demo.py +45 -0
  181. autocoder/common/llms/test_quick_model.py +116 -0
  182. autocoder/common/llms/test_remove_functionality.py +182 -0
  183. autocoder/common/llms/tests/__init__.py +1 -0
  184. autocoder/common/llms/tests/test_manager.py +330 -0
  185. autocoder/common/llms/tests/test_registry.py +364 -0
  186. autocoder/common/mcp_tools/__init__.py +62 -0
  187. autocoder/common/{mcp_tools.py → mcp_tools/executor.py} +49 -40
  188. autocoder/common/{mcp_hub.py → mcp_tools/hub.py} +42 -68
  189. autocoder/common/{mcp_server_install.py → mcp_tools/installer.py} +16 -28
  190. autocoder/common/{mcp_server.py → mcp_tools/server.py} +176 -48
  191. autocoder/common/mcp_tools/test_keyboard_interrupt.py +93 -0
  192. autocoder/common/mcp_tools/test_mcp_tools.py +391 -0
  193. autocoder/common/{mcp_server_types.py → mcp_tools/types.py} +121 -48
  194. autocoder/common/mcp_tools/verify_functionality.py +202 -0
  195. autocoder/common/model_speed_tester.py +32 -26
  196. autocoder/common/priority_directory_finder/__init__.py +142 -0
  197. autocoder/common/priority_directory_finder/examples.py +230 -0
  198. autocoder/common/priority_directory_finder/finder.py +283 -0
  199. autocoder/common/priority_directory_finder/models.py +236 -0
  200. autocoder/common/priority_directory_finder/test_priority_directory_finder.py +431 -0
  201. autocoder/common/project_scanner/__init__.py +18 -0
  202. autocoder/common/project_scanner/compat.py +77 -0
  203. autocoder/common/project_scanner/scanner.py +436 -0
  204. autocoder/common/project_tracker/__init__.py +27 -0
  205. autocoder/common/project_tracker/api.py +228 -0
  206. autocoder/common/project_tracker/demo.py +272 -0
  207. autocoder/common/project_tracker/tracker.py +487 -0
  208. autocoder/common/project_tracker/types.py +53 -0
  209. autocoder/common/pruner/__init__.py +67 -0
  210. autocoder/common/pruner/agentic_conversation_pruner.py +746 -0
  211. autocoder/common/{context_pruner.py → pruner/context_pruner.py} +137 -40
  212. autocoder/common/pruner/conversation_message_ids_api.py +386 -0
  213. autocoder/common/pruner/conversation_message_ids_manager.py +347 -0
  214. autocoder/common/pruner/conversation_message_ids_pruner.py +473 -0
  215. autocoder/common/pruner/conversation_normalizer.py +347 -0
  216. autocoder/common/{conversation_pruner.py → pruner/conversation_pruner.py} +26 -6
  217. autocoder/common/pruner/test_agentic_conversation_pruner.py +784 -0
  218. autocoder/common/pruner/test_context_pruner.py +546 -0
  219. autocoder/common/pruner/test_conversation_normalizer.py +502 -0
  220. autocoder/common/pruner/test_tool_content_detector.py +324 -0
  221. autocoder/common/pruner/tool_content_detector.py +227 -0
  222. autocoder/common/pruner/tools/__init__.py +18 -0
  223. autocoder/common/pruner/tools/query_message_ids.py +264 -0
  224. autocoder/common/pruner/tools/test_agentic_pruning_logic.py +432 -0
  225. autocoder/common/pruner/tools/test_message_ids_pruning_only.py +192 -0
  226. autocoder/common/pull_requests/__init__.py +9 -1
  227. autocoder/common/pull_requests/utils.py +122 -1
  228. autocoder/common/rag_manager/rag_manager.py +36 -40
  229. autocoder/common/rulefiles/__init__.py +53 -1
  230. autocoder/common/rulefiles/api.py +250 -0
  231. autocoder/common/rulefiles/core/__init__.py +14 -0
  232. autocoder/common/rulefiles/core/manager.py +241 -0
  233. autocoder/common/rulefiles/core/selector.py +805 -0
  234. autocoder/common/rulefiles/models/__init__.py +20 -0
  235. autocoder/common/rulefiles/models/index.py +16 -0
  236. autocoder/common/rulefiles/models/init_rule.py +18 -0
  237. autocoder/common/rulefiles/models/rule_file.py +18 -0
  238. autocoder/common/rulefiles/models/rule_relevance.py +14 -0
  239. autocoder/common/rulefiles/models/summary.py +16 -0
  240. autocoder/common/rulefiles/test_rulefiles.py +776 -0
  241. autocoder/common/rulefiles/utils/__init__.py +34 -0
  242. autocoder/common/rulefiles/utils/monitor.py +86 -0
  243. autocoder/common/rulefiles/utils/parser.py +230 -0
  244. autocoder/common/save_formatted_log.py +67 -10
  245. autocoder/common/search_replace.py +8 -1
  246. autocoder/common/search_replace_patch/__init__.py +24 -0
  247. autocoder/common/search_replace_patch/base.py +115 -0
  248. autocoder/common/search_replace_patch/manager.py +248 -0
  249. autocoder/common/search_replace_patch/patch_replacer.py +304 -0
  250. autocoder/common/search_replace_patch/similarity_replacer.py +306 -0
  251. autocoder/common/search_replace_patch/string_replacer.py +181 -0
  252. autocoder/common/search_replace_patch/tests/__init__.py +3 -0
  253. autocoder/common/search_replace_patch/tests/run_tests.py +126 -0
  254. autocoder/common/search_replace_patch/tests/test_base.py +188 -0
  255. autocoder/common/search_replace_patch/tests/test_empty_line_insert.py +233 -0
  256. autocoder/common/search_replace_patch/tests/test_integration.py +389 -0
  257. autocoder/common/search_replace_patch/tests/test_manager.py +351 -0
  258. autocoder/common/search_replace_patch/tests/test_patch_replacer.py +316 -0
  259. autocoder/common/search_replace_patch/tests/test_regex_replacer.py +306 -0
  260. autocoder/common/search_replace_patch/tests/test_similarity_replacer.py +384 -0
  261. autocoder/common/shell_commands/__init__.py +197 -0
  262. autocoder/common/shell_commands/background_process_notifier.py +346 -0
  263. autocoder/common/shell_commands/command_executor.py +1127 -0
  264. autocoder/common/shell_commands/error_recovery.py +541 -0
  265. autocoder/common/shell_commands/exceptions.py +120 -0
  266. autocoder/common/shell_commands/interactive_executor.py +476 -0
  267. autocoder/common/shell_commands/interactive_pexpect_process.py +623 -0
  268. autocoder/common/shell_commands/interactive_process.py +744 -0
  269. autocoder/common/shell_commands/interactive_session_manager.py +1014 -0
  270. autocoder/common/shell_commands/monitoring.py +529 -0
  271. autocoder/common/shell_commands/process_cleanup.py +386 -0
  272. autocoder/common/shell_commands/process_manager.py +606 -0
  273. autocoder/common/shell_commands/test_interactive_pexpect_process.py +281 -0
  274. autocoder/common/shell_commands/tests/__init__.py +6 -0
  275. autocoder/common/shell_commands/tests/conftest.py +118 -0
  276. autocoder/common/shell_commands/tests/test_background_process_notifier.py +703 -0
  277. autocoder/common/shell_commands/tests/test_command_executor.py +448 -0
  278. autocoder/common/shell_commands/tests/test_error_recovery.py +305 -0
  279. autocoder/common/shell_commands/tests/test_exceptions.py +299 -0
  280. autocoder/common/shell_commands/tests/test_execute_batch.py +588 -0
  281. autocoder/common/shell_commands/tests/test_indented_batch_commands.py +244 -0
  282. autocoder/common/shell_commands/tests/test_integration.py +664 -0
  283. autocoder/common/shell_commands/tests/test_monitoring.py +546 -0
  284. autocoder/common/shell_commands/tests/test_performance.py +632 -0
  285. autocoder/common/shell_commands/tests/test_process_cleanup.py +397 -0
  286. autocoder/common/shell_commands/tests/test_process_manager.py +606 -0
  287. autocoder/common/shell_commands/tests/test_timeout_config.py +343 -0
  288. autocoder/common/shell_commands/tests/test_timeout_manager.py +520 -0
  289. autocoder/common/shell_commands/timeout_config.py +315 -0
  290. autocoder/common/shell_commands/timeout_manager.py +352 -0
  291. autocoder/common/terminal_paste/__init__.py +14 -0
  292. autocoder/common/terminal_paste/demo.py +145 -0
  293. autocoder/common/terminal_paste/demo_paste_functionality.py +95 -0
  294. autocoder/common/terminal_paste/paste_handler.py +200 -0
  295. autocoder/common/terminal_paste/paste_manager.py +118 -0
  296. autocoder/common/terminal_paste/tests/__init__.py +1 -0
  297. autocoder/common/terminal_paste/tests/test_paste_handler.py +182 -0
  298. autocoder/common/terminal_paste/tests/test_paste_manager.py +126 -0
  299. autocoder/common/terminal_paste/utils.py +163 -0
  300. autocoder/common/test_autocoder_args.py +232 -0
  301. autocoder/common/test_env_manager.py +173 -0
  302. autocoder/common/test_env_manager_integration.py +159 -0
  303. autocoder/common/text_similarity/__init__.py +9 -0
  304. autocoder/common/text_similarity/demo.py +216 -0
  305. autocoder/common/text_similarity/examples.py +266 -0
  306. autocoder/common/text_similarity/test_text_similarity.py +306 -0
  307. autocoder/common/text_similarity/text_similarity.py +194 -0
  308. autocoder/common/text_similarity/utils.py +125 -0
  309. autocoder/common/todos/__init__.py +61 -0
  310. autocoder/common/todos/cache/__init__.py +16 -0
  311. autocoder/common/todos/cache/base_cache.py +89 -0
  312. autocoder/common/todos/cache/cache_manager.py +228 -0
  313. autocoder/common/todos/cache/memory_cache.py +225 -0
  314. autocoder/common/todos/config.py +155 -0
  315. autocoder/common/todos/exceptions.py +35 -0
  316. autocoder/common/todos/get_todo_manager.py +161 -0
  317. autocoder/common/todos/manager.py +537 -0
  318. autocoder/common/todos/models.py +239 -0
  319. autocoder/common/todos/storage/__init__.py +14 -0
  320. autocoder/common/todos/storage/base_storage.py +76 -0
  321. autocoder/common/todos/storage/file_storage.py +278 -0
  322. autocoder/common/tokens/__init__.py +15 -0
  323. autocoder/common/tokens/counter.py +44 -2
  324. autocoder/common/tools_manager/__init__.py +17 -0
  325. autocoder/common/tools_manager/examples.py +162 -0
  326. autocoder/common/tools_manager/manager.py +385 -0
  327. autocoder/common/tools_manager/models.py +39 -0
  328. autocoder/common/tools_manager/test_tools_manager.py +303 -0
  329. autocoder/common/tools_manager/utils.py +191 -0
  330. autocoder/common/v2/agent/agentic_callbacks.py +270 -0
  331. autocoder/common/v2/agent/agentic_edit.py +2729 -2052
  332. autocoder/common/v2/agent/agentic_edit_change_manager.py +474 -0
  333. autocoder/common/v2/agent/agentic_edit_tools/__init__.py +43 -2
  334. autocoder/common/v2/agent/agentic_edit_tools/ac_mod_list_tool_resolver.py +279 -0
  335. autocoder/common/v2/agent/agentic_edit_tools/ac_mod_read_tool_resolver.py +40 -0
  336. autocoder/common/v2/agent/agentic_edit_tools/ac_mod_write_tool_resolver.py +52 -0
  337. autocoder/common/v2/agent/agentic_edit_tools/ask_followup_question_tool_resolver.py +8 -0
  338. autocoder/common/v2/agent/agentic_edit_tools/background_task_tool_resolver.py +1167 -0
  339. autocoder/common/v2/agent/agentic_edit_tools/base_tool_resolver.py +2 -2
  340. autocoder/common/v2/agent/agentic_edit_tools/conversation_message_ids_read_tool_resolver.py +214 -0
  341. autocoder/common/v2/agent/agentic_edit_tools/conversation_message_ids_write_tool_resolver.py +299 -0
  342. autocoder/common/v2/agent/agentic_edit_tools/count_tokens_tool_resolver.py +290 -0
  343. autocoder/common/v2/agent/agentic_edit_tools/execute_command_tool_resolver.py +565 -30
  344. autocoder/common/v2/agent/agentic_edit_tools/execute_workflow_tool_resolver.py +485 -0
  345. autocoder/common/v2/agent/agentic_edit_tools/extract_to_text_tool_resolver.py +225 -0
  346. autocoder/common/v2/agent/agentic_edit_tools/lint_report.py +79 -0
  347. autocoder/common/v2/agent/agentic_edit_tools/linter_config_models.py +343 -0
  348. autocoder/common/v2/agent/agentic_edit_tools/linter_enabled_tool_resolver.py +189 -0
  349. autocoder/common/v2/agent/agentic_edit_tools/list_files_tool_resolver.py +169 -101
  350. autocoder/common/v2/agent/agentic_edit_tools/load_extra_document_tool_resolver.py +349 -0
  351. autocoder/common/v2/agent/agentic_edit_tools/read_file_tool_resolver.py +244 -51
  352. autocoder/common/v2/agent/agentic_edit_tools/replace_in_file_tool_resolver.py +667 -147
  353. autocoder/common/v2/agent/agentic_edit_tools/run_named_subagents_tool_resolver.py +691 -0
  354. autocoder/common/v2/agent/agentic_edit_tools/search_files_tool_resolver.py +409 -140
  355. autocoder/common/v2/agent/agentic_edit_tools/session_interactive_tool_resolver.py +115 -0
  356. autocoder/common/v2/agent/agentic_edit_tools/session_start_tool_resolver.py +190 -0
  357. autocoder/common/v2/agent/agentic_edit_tools/session_stop_tool_resolver.py +76 -0
  358. autocoder/common/v2/agent/agentic_edit_tools/test_write_to_file_tool_resolver.py +209 -194
  359. autocoder/common/v2/agent/agentic_edit_tools/todo_read_tool_resolver.py +135 -0
  360. autocoder/common/v2/agent/agentic_edit_tools/todo_write_tool_resolver.py +328 -0
  361. autocoder/common/v2/agent/agentic_edit_tools/use_mcp_tool_resolver.py +2 -2
  362. autocoder/common/v2/agent/agentic_edit_tools/web_crawl_tool_resolver.py +557 -0
  363. autocoder/common/v2/agent/agentic_edit_tools/web_search_tool_resolver.py +600 -0
  364. autocoder/common/v2/agent/agentic_edit_tools/write_to_file_tool_resolver.py +56 -121
  365. autocoder/common/v2/agent/agentic_edit_types.py +386 -10
  366. autocoder/common/v2/agent/runner/__init__.py +31 -0
  367. autocoder/common/v2/agent/runner/base_runner.py +92 -0
  368. autocoder/common/v2/agent/runner/file_based_event_runner.py +217 -0
  369. autocoder/common/v2/agent/runner/sdk_runner.py +182 -0
  370. autocoder/common/v2/agent/runner/terminal_runner.py +396 -0
  371. autocoder/common/v2/agent/runner/tool_display.py +589 -0
  372. autocoder/common/v2/agent/test_agentic_callbacks.py +265 -0
  373. autocoder/common/v2/agent/test_agentic_edit.py +194 -0
  374. autocoder/common/v2/agent/tool_caller/__init__.py +24 -0
  375. autocoder/common/v2/agent/tool_caller/default_tool_resolver_map.py +135 -0
  376. autocoder/common/v2/agent/tool_caller/integration_test.py +172 -0
  377. autocoder/common/v2/agent/tool_caller/plugins/__init__.py +14 -0
  378. autocoder/common/v2/agent/tool_caller/plugins/base_plugin.py +126 -0
  379. autocoder/common/v2/agent/tool_caller/plugins/examples/__init__.py +13 -0
  380. autocoder/common/v2/agent/tool_caller/plugins/examples/logging_plugin.py +164 -0
  381. autocoder/common/v2/agent/tool_caller/plugins/examples/security_filter_plugin.py +198 -0
  382. autocoder/common/v2/agent/tool_caller/plugins/plugin_interface.py +141 -0
  383. autocoder/common/v2/agent/tool_caller/test_tool_caller.py +278 -0
  384. autocoder/common/v2/agent/tool_caller/tool_call_plugin_manager.py +331 -0
  385. autocoder/common/v2/agent/tool_caller/tool_caller.py +337 -0
  386. autocoder/common/v2/agent/tool_caller/usage_example.py +193 -0
  387. autocoder/common/v2/code_agentic_editblock_manager.py +4 -4
  388. autocoder/common/v2/code_auto_generate.py +136 -78
  389. autocoder/common/v2/code_auto_generate_diff.py +135 -79
  390. autocoder/common/v2/code_auto_generate_editblock.py +174 -99
  391. autocoder/common/v2/code_auto_generate_strict_diff.py +151 -71
  392. autocoder/common/v2/code_auto_merge.py +1 -1
  393. autocoder/common/v2/code_auto_merge_editblock.py +13 -1
  394. autocoder/common/v2/code_diff_manager.py +3 -3
  395. autocoder/common/v2/code_editblock_manager.py +4 -14
  396. autocoder/common/v2/code_manager.py +1 -1
  397. autocoder/common/v2/code_strict_diff_manager.py +2 -2
  398. autocoder/common/wrap_llm_hint/__init__.py +10 -0
  399. autocoder/common/wrap_llm_hint/test_wrap_llm_hint.py +1067 -0
  400. autocoder/common/wrap_llm_hint/utils.py +432 -0
  401. autocoder/common/wrap_llm_hint/wrap_llm_hint.py +323 -0
  402. autocoder/completer/__init__.py +8 -0
  403. autocoder/completer/command_completer_v2.py +1051 -0
  404. autocoder/default_project/__init__.py +501 -0
  405. autocoder/dispacher/__init__.py +4 -12
  406. autocoder/dispacher/actions/action.py +165 -7
  407. autocoder/dispacher/actions/plugins/action_regex_project.py +2 -2
  408. autocoder/index/entry.py +117 -125
  409. autocoder/{agent → index/filter}/agentic_filter.py +323 -334
  410. autocoder/index/filter/normal_filter.py +5 -11
  411. autocoder/index/filter/quick_filter.py +1 -1
  412. autocoder/index/index.py +36 -9
  413. autocoder/index/tests/__init__.py +1 -0
  414. autocoder/index/tests/run_tests.py +195 -0
  415. autocoder/index/tests/test_entry.py +303 -0
  416. autocoder/index/tests/test_index_manager.py +314 -0
  417. autocoder/index/tests/test_module_integration.py +300 -0
  418. autocoder/index/tests/test_symbols_utils.py +183 -0
  419. autocoder/inner/__init__.py +4 -0
  420. autocoder/inner/agentic.py +932 -0
  421. autocoder/inner/async_command_handler.py +992 -0
  422. autocoder/inner/conversation_command_handlers.py +623 -0
  423. autocoder/inner/merge_command_handler.py +213 -0
  424. autocoder/inner/queue_command_handler.py +684 -0
  425. autocoder/models.py +95 -266
  426. autocoder/plugins/git_helper_plugin.py +31 -29
  427. autocoder/plugins/token_helper_plugin.py +156 -37
  428. autocoder/pyproject/__init__.py +32 -29
  429. autocoder/rag/agentic_rag.py +215 -75
  430. autocoder/rag/cache/simple_cache.py +1 -2
  431. autocoder/rag/loaders/image_loader.py +1 -1
  432. autocoder/rag/long_context_rag.py +42 -26
  433. autocoder/rag/qa_conversation_strategy.py +1 -1
  434. autocoder/rag/terminal/__init__.py +17 -0
  435. autocoder/rag/terminal/args.py +581 -0
  436. autocoder/rag/terminal/bootstrap.py +61 -0
  437. autocoder/rag/terminal/command_handlers.py +653 -0
  438. autocoder/rag/terminal/formatters/__init__.py +20 -0
  439. autocoder/rag/terminal/formatters/base.py +70 -0
  440. autocoder/rag/terminal/formatters/json_format.py +66 -0
  441. autocoder/rag/terminal/formatters/stream_json.py +95 -0
  442. autocoder/rag/terminal/formatters/text.py +28 -0
  443. autocoder/rag/terminal/init.py +120 -0
  444. autocoder/rag/terminal/utils.py +106 -0
  445. autocoder/rag/test_agentic_rag.py +389 -0
  446. autocoder/rag/test_doc_filter.py +3 -3
  447. autocoder/rag/test_long_context_rag.py +1 -1
  448. autocoder/rag/test_token_limiter.py +517 -10
  449. autocoder/rag/token_counter.py +3 -0
  450. autocoder/rag/token_limiter.py +19 -15
  451. autocoder/rag/tools/__init__.py +26 -2
  452. autocoder/rag/tools/bochaai_example.py +343 -0
  453. autocoder/rag/tools/bochaai_sdk.py +541 -0
  454. autocoder/rag/tools/metaso_example.py +268 -0
  455. autocoder/rag/tools/metaso_sdk.py +417 -0
  456. autocoder/rag/tools/recall_tool.py +28 -7
  457. autocoder/rag/tools/run_integration_tests.py +204 -0
  458. autocoder/rag/tools/test_all_providers.py +318 -0
  459. autocoder/rag/tools/test_bochaai_integration.py +482 -0
  460. autocoder/rag/tools/test_final_integration.py +215 -0
  461. autocoder/rag/tools/test_metaso_integration.py +424 -0
  462. autocoder/rag/tools/test_metaso_real.py +171 -0
  463. autocoder/rag/tools/test_web_crawl_tool.py +639 -0
  464. autocoder/rag/tools/test_web_search_tool.py +509 -0
  465. autocoder/rag/tools/todo_read_tool.py +202 -0
  466. autocoder/rag/tools/todo_write_tool.py +412 -0
  467. autocoder/rag/tools/web_crawl_tool.py +634 -0
  468. autocoder/rag/tools/web_search_tool.py +558 -0
  469. autocoder/rag/tools/web_tools_example.py +119 -0
  470. autocoder/rag/types.py +16 -0
  471. autocoder/rag/variable_holder.py +4 -2
  472. autocoder/rags.py +86 -79
  473. autocoder/regexproject/__init__.py +23 -21
  474. autocoder/run_context.py +9 -0
  475. autocoder/sdk/__init__.py +50 -161
  476. autocoder/sdk/api.py +370 -0
  477. autocoder/sdk/async_runner/__init__.py +26 -0
  478. autocoder/sdk/async_runner/async_executor.py +650 -0
  479. autocoder/sdk/async_runner/async_handler.py +356 -0
  480. autocoder/sdk/async_runner/markdown_processor.py +595 -0
  481. autocoder/sdk/async_runner/task_metadata.py +284 -0
  482. autocoder/sdk/async_runner/worktree_manager.py +438 -0
  483. autocoder/sdk/cli/__init__.py +2 -5
  484. autocoder/sdk/cli/formatters.py +28 -204
  485. autocoder/sdk/cli/handlers.py +77 -44
  486. autocoder/sdk/cli/main.py +158 -170
  487. autocoder/sdk/cli/options.py +95 -22
  488. autocoder/sdk/constants.py +139 -51
  489. autocoder/sdk/core/auto_coder_core.py +484 -267
  490. autocoder/sdk/core/bridge.py +298 -118
  491. autocoder/sdk/exceptions.py +18 -12
  492. autocoder/sdk/formatters/__init__.py +19 -0
  493. autocoder/sdk/formatters/input.py +64 -0
  494. autocoder/sdk/formatters/output.py +247 -0
  495. autocoder/sdk/formatters/stream.py +54 -0
  496. autocoder/sdk/models/__init__.py +6 -5
  497. autocoder/sdk/models/options.py +55 -18
  498. autocoder/sdk/utils/formatters.py +27 -195
  499. autocoder/suffixproject/__init__.py +28 -25
  500. autocoder/terminal/__init__.py +14 -0
  501. autocoder/terminal/app.py +454 -0
  502. autocoder/terminal/args.py +32 -0
  503. autocoder/terminal/bootstrap.py +178 -0
  504. autocoder/terminal/command_processor.py +521 -0
  505. autocoder/terminal/command_registry.py +57 -0
  506. autocoder/terminal/help.py +97 -0
  507. autocoder/terminal/tasks/__init__.py +5 -0
  508. autocoder/terminal/tasks/background.py +77 -0
  509. autocoder/terminal/tasks/task_event.py +70 -0
  510. autocoder/terminal/ui/__init__.py +13 -0
  511. autocoder/terminal/ui/completer.py +268 -0
  512. autocoder/terminal/ui/keybindings.py +75 -0
  513. autocoder/terminal/ui/session.py +41 -0
  514. autocoder/terminal/ui/toolbar.py +64 -0
  515. autocoder/terminal/utils/__init__.py +13 -0
  516. autocoder/terminal/utils/errors.py +18 -0
  517. autocoder/terminal/utils/paths.py +19 -0
  518. autocoder/terminal/utils/shell.py +43 -0
  519. autocoder/terminal_v3/__init__.py +10 -0
  520. autocoder/terminal_v3/app.py +201 -0
  521. autocoder/terminal_v3/handlers/__init__.py +5 -0
  522. autocoder/terminal_v3/handlers/command_handler.py +131 -0
  523. autocoder/terminal_v3/models/__init__.py +6 -0
  524. autocoder/terminal_v3/models/conversation_buffer.py +214 -0
  525. autocoder/terminal_v3/models/message.py +50 -0
  526. autocoder/terminal_v3/models/tool_display.py +247 -0
  527. autocoder/terminal_v3/ui/__init__.py +7 -0
  528. autocoder/terminal_v3/ui/keybindings.py +56 -0
  529. autocoder/terminal_v3/ui/layout.py +141 -0
  530. autocoder/terminal_v3/ui/styles.py +43 -0
  531. autocoder/tsproject/__init__.py +23 -23
  532. autocoder/utils/auto_coder_utils/chat_stream_out.py +1 -1
  533. autocoder/utils/llms.py +88 -80
  534. autocoder/utils/math_utils.py +101 -0
  535. autocoder/utils/model_provider_selector.py +16 -4
  536. autocoder/utils/operate_config_api.py +33 -5
  537. autocoder/utils/thread_utils.py +2 -2
  538. autocoder/version.py +4 -2
  539. autocoder/workflow_agents/__init__.py +84 -0
  540. autocoder/workflow_agents/agent.py +143 -0
  541. autocoder/workflow_agents/exceptions.py +573 -0
  542. autocoder/workflow_agents/executor.py +489 -0
  543. autocoder/workflow_agents/loader.py +737 -0
  544. autocoder/workflow_agents/runner.py +267 -0
  545. autocoder/workflow_agents/types.py +172 -0
  546. autocoder/workflow_agents/utils.py +434 -0
  547. autocoder/workflow_agents/workflow_manager.py +211 -0
  548. auto_coder-0.1.400.dist-info/METADATA +0 -396
  549. auto_coder-0.1.400.dist-info/RECORD +0 -425
  550. auto_coder-0.1.400.dist-info/licenses/LICENSE +0 -201
  551. autocoder/auto_coder_server.py +0 -672
  552. autocoder/benchmark.py +0 -138
  553. autocoder/common/ac_style_command_parser/example.py +0 -7
  554. autocoder/common/cleaner.py +0 -31
  555. autocoder/common/command_completer_v2.py +0 -615
  556. autocoder/common/directory_cache/__init__.py +0 -1
  557. autocoder/common/directory_cache/cache.py +0 -192
  558. autocoder/common/directory_cache/test_cache.py +0 -190
  559. autocoder/common/file_checkpoint/examples.py +0 -217
  560. autocoder/common/llm_friendly_package_example.py +0 -138
  561. autocoder/common/llm_friendly_package_test.py +0 -63
  562. autocoder/common/pull_requests/test_module.py +0 -1
  563. autocoder/common/rulefiles/autocoderrules_utils.py +0 -484
  564. autocoder/common/text.py +0 -30
  565. autocoder/common/v2/agent/agentic_edit_tools/list_package_info_tool_resolver.py +0 -42
  566. autocoder/common/v2/agent/agentic_edit_tools/test_execute_command_tool_resolver.py +0 -70
  567. autocoder/common/v2/agent/agentic_edit_tools/test_search_files_tool_resolver.py +0 -163
  568. autocoder/common/v2/agent/agentic_tool_display.py +0 -183
  569. autocoder/plugins/dynamic_completion_example.py +0 -148
  570. autocoder/plugins/sample_plugin.py +0 -160
  571. autocoder/sdk/cli/__main__.py +0 -26
  572. autocoder/sdk/cli/completion_wrapper.py +0 -38
  573. autocoder/sdk/cli/install_completion.py +0 -301
  574. autocoder/sdk/models/messages.py +0 -209
  575. autocoder/sdk/session/__init__.py +0 -32
  576. autocoder/sdk/session/session.py +0 -106
  577. autocoder/sdk/session/session_manager.py +0 -56
  578. {auto_coder-0.1.400.dist-info → auto_coder-2.0.0.dist-info}/top_level.txt +0 -0
  579. /autocoder/{sdk/example.py → common/agent_query_queue/__init__.py} +0 -0
@@ -0,0 +1,536 @@
1
+ """
2
+ Test suite for LLM Friendly Package Manager
3
+
4
+ This module provides comprehensive tests for all package manager functionality
5
+ including library management, documentation handling, repository operations,
6
+ and integration with core_config.
7
+ """
8
+
9
+ import os
10
+ import tempfile
11
+ import shutil
12
+ import pytest
13
+ from unittest.mock import Mock, patch, MagicMock
14
+ from pathlib import Path
15
+
16
+ from autocoder.common.llm_friendly_package import (
17
+ LLMFriendlyPackageManager,
18
+ get_package_manager,
19
+ LibraryInfo,
20
+ RepositoryInfo,
21
+ PackageDoc
22
+ )
23
+
24
+
25
+ class TestLLMFriendlyPackageManager:
26
+ """Test suite for LLMFriendlyPackageManager"""
27
+
28
+ @pytest.fixture
29
+ def temp_project_root(self):
30
+ """Create a temporary project root directory"""
31
+ temp_dir = tempfile.mkdtemp()
32
+ yield temp_dir
33
+ shutil.rmtree(temp_dir, ignore_errors=True)
34
+
35
+ @pytest.fixture
36
+ def mock_memory_manager(self):
37
+ """Mock memory manager for testing"""
38
+ mock_manager = Mock()
39
+ mock_manager.get_libs.return_value = {}
40
+ mock_manager.get_config.return_value = "https://github.com/allwefantasy/llm_friendly_packages"
41
+ mock_manager.has_lib.return_value = False
42
+ mock_manager.add_lib.return_value = None
43
+ mock_manager.remove_lib.return_value = True
44
+ mock_manager.set_config.return_value = None
45
+ return mock_manager
46
+
47
+ @pytest.fixture
48
+ def manager(self, temp_project_root, mock_memory_manager):
49
+ """Create a package manager instance for testing"""
50
+ with patch('autocoder.common.llm_friendly_package.main_manager.get_memory_manager') as mock_get_memory:
51
+ mock_get_memory.return_value = mock_memory_manager
52
+ return LLMFriendlyPackageManager(temp_project_root)
53
+
54
+ @pytest.fixture
55
+ def mock_repo_structure(self, manager):
56
+ """Create a mock repository structure for testing"""
57
+ repo_dir = manager.llm_friendly_packages_dir
58
+ os.makedirs(repo_dir, exist_ok=True)
59
+
60
+ # Create test library structure
61
+ test_lib_path = os.path.join(repo_dir, "github.com", "testuser", "testlib")
62
+ os.makedirs(test_lib_path, exist_ok=True)
63
+
64
+ # Create test markdown file
65
+ readme_path = os.path.join(test_lib_path, "README.md")
66
+ with open(readme_path, "w") as f:
67
+ f.write("# Test Library\n\nThis is a test library for LLM.")
68
+
69
+ # Create another test library
70
+ test_lib2_path = os.path.join(repo_dir, "github.com", "testuser", "testlib2")
71
+ os.makedirs(test_lib2_path, exist_ok=True)
72
+
73
+ docs_path = os.path.join(test_lib2_path, "docs.md")
74
+ with open(docs_path, "w") as f:
75
+ f.write("# Test Library 2 Documentation\n\nDetailed docs here.")
76
+
77
+ return repo_dir
78
+
79
+ def test_manager_initialization(self, temp_project_root, mock_memory_manager):
80
+ """Test manager initialization"""
81
+ with patch('autocoder.common.llm_friendly_package.main_manager.get_memory_manager') as mock_get_memory:
82
+ mock_get_memory.return_value = mock_memory_manager
83
+
84
+ manager = LLMFriendlyPackageManager(temp_project_root)
85
+
86
+ assert manager.project_root == temp_project_root
87
+ assert manager.memory_manager == mock_memory_manager
88
+ assert manager.lib_dir == os.path.join(temp_project_root, ".auto-coder", "libs")
89
+ assert os.path.exists(manager.lib_dir)
90
+
91
+ def test_get_package_manager_function(self, temp_project_root, mock_memory_manager):
92
+ """Test the convenience function"""
93
+ with patch('autocoder.common.llm_friendly_package.main_manager.get_memory_manager') as mock_get_memory:
94
+ mock_get_memory.return_value = mock_memory_manager
95
+
96
+ manager = get_package_manager(temp_project_root)
97
+ assert isinstance(manager, LLMFriendlyPackageManager)
98
+ assert manager.project_root == temp_project_root
99
+
100
+ def test_default_proxy_url(self, manager):
101
+ """Test default proxy URL"""
102
+ assert manager.default_proxy_url == "https://github.com/allwefantasy/llm_friendly_packages"
103
+
104
+ def test_list_added_libraries_empty(self, manager):
105
+ """Test listing libraries when none are added"""
106
+ libs = manager.list_added_libraries()
107
+ assert libs == []
108
+
109
+ def test_list_added_libraries_with_data(self, manager, mock_memory_manager):
110
+ """Test listing libraries with data"""
111
+ mock_memory_manager.get_libs.return_value = {"numpy": {}, "pandas": {}}
112
+
113
+ libs = manager.list_added_libraries()
114
+ assert set(libs) == {"numpy", "pandas"}
115
+
116
+ def test_add_library_success(self, manager, mock_memory_manager):
117
+ """Test successful library addition"""
118
+ mock_memory_manager.has_lib.return_value = False
119
+
120
+ with patch.object(manager, '_clone_repository', return_value=True):
121
+ result = manager.add_library("test-lib")
122
+
123
+ assert result is True
124
+ mock_memory_manager.add_lib.assert_called_once_with("test-lib", {})
125
+
126
+ def test_add_library_already_exists(self, manager, mock_memory_manager):
127
+ """Test adding library that already exists"""
128
+ mock_memory_manager.has_lib.return_value = True
129
+
130
+ with patch.object(manager, '_clone_repository', return_value=True):
131
+ result = manager.add_library("existing-lib")
132
+
133
+ assert result is False
134
+ mock_memory_manager.add_lib.assert_not_called()
135
+
136
+ def test_add_library_clone_fails(self, manager, mock_memory_manager):
137
+ """Test library addition when repository clone fails"""
138
+ mock_memory_manager.has_lib.return_value = False
139
+
140
+ with patch.object(manager, '_clone_repository', return_value=False):
141
+ result = manager.add_library("test-lib")
142
+
143
+ assert result is False
144
+ mock_memory_manager.add_lib.assert_not_called()
145
+
146
+ def test_remove_library_success(self, manager, mock_memory_manager):
147
+ """Test successful library removal"""
148
+ mock_memory_manager.has_lib.return_value = True
149
+
150
+ result = manager.remove_library("test-lib")
151
+
152
+ assert result is True
153
+ mock_memory_manager.remove_lib.assert_called_once_with("test-lib")
154
+
155
+ def test_remove_library_not_found(self, manager, mock_memory_manager):
156
+ """Test removing library that doesn't exist"""
157
+ mock_memory_manager.has_lib.return_value = False
158
+
159
+ result = manager.remove_library("nonexistent-lib")
160
+
161
+ assert result is False
162
+ mock_memory_manager.remove_lib.assert_not_called()
163
+
164
+ def test_has_library(self, manager, mock_memory_manager):
165
+ """Test checking if library exists"""
166
+ mock_memory_manager.has_lib.side_effect = lambda name: name == "existing-lib"
167
+
168
+ assert manager.has_library("existing-lib") is True
169
+ assert manager.has_library("nonexistent-lib") is False
170
+
171
+ def test_list_all_available_libraries_no_repo(self, manager):
172
+ """Test listing available libraries when repository doesn't exist"""
173
+ libs = manager.list_all_available_libraries()
174
+ assert libs == []
175
+
176
+ def test_list_all_available_libraries_with_repo(self, manager, mock_repo_structure, mock_memory_manager):
177
+ """Test listing available libraries with repository"""
178
+ mock_memory_manager.get_libs.return_value = {"testlib": {}}
179
+
180
+ libs = manager.list_all_available_libraries()
181
+
182
+ assert len(libs) == 2
183
+
184
+ # Check first library
185
+ lib1 = next(lib for lib in libs if lib.lib_name == "testlib")
186
+ assert lib1.domain == "github.com"
187
+ assert lib1.username == "testuser"
188
+ assert lib1.lib_name == "testlib"
189
+ assert lib1.full_path == "testuser/testlib"
190
+ assert lib1.is_added is True
191
+ assert lib1.has_md_files is True
192
+
193
+ # Check second library
194
+ lib2 = next(lib for lib in libs if lib.lib_name == "testlib2")
195
+ assert lib2.is_added is False
196
+
197
+ def test_get_package_path_found(self, manager, mock_repo_structure):
198
+ """Test getting package path when package exists"""
199
+ path = manager.get_package_path("testlib")
200
+ expected_path = os.path.join(mock_repo_structure, "github.com", "testuser", "testlib")
201
+ assert path == expected_path
202
+
203
+ # Test with full path format
204
+ path2 = manager.get_package_path("testuser/testlib")
205
+ assert path2 == expected_path
206
+
207
+ def test_get_package_path_not_found(self, manager, mock_repo_structure):
208
+ """Test getting package path when package doesn't exist"""
209
+ path = manager.get_package_path("nonexistent")
210
+ assert path is None
211
+
212
+ def test_get_package_path_no_repo(self, manager):
213
+ """Test getting package path when repository doesn't exist"""
214
+ path = manager.get_package_path("testlib")
215
+ assert path is None
216
+
217
+ def test_get_docs_no_repo(self, manager):
218
+ """Test getting docs when repository doesn't exist"""
219
+ docs = manager.get_docs()
220
+ assert docs == []
221
+
222
+ def test_get_docs_content(self, manager, mock_repo_structure, mock_memory_manager):
223
+ """Test getting documentation content"""
224
+ mock_memory_manager.get_libs.return_value = {"testlib": {}, "testlib2": {}}
225
+
226
+ # Get all docs content
227
+ docs = manager.get_docs(return_paths=False)
228
+ assert len(docs) == 2
229
+ assert "# Test Library" in docs[0]
230
+ assert "# Test Library 2 Documentation" in docs[1]
231
+
232
+ # Get specific package docs
233
+ specific_docs = manager.get_docs("testlib", return_paths=False)
234
+ assert len(specific_docs) == 1
235
+ assert "# Test Library" in specific_docs[0]
236
+
237
+ def test_get_docs_paths(self, manager, mock_repo_structure, mock_memory_manager):
238
+ """Test getting documentation paths"""
239
+ mock_memory_manager.get_libs.return_value = {"testlib": {}, "testlib2": {}}
240
+
241
+ # Get all docs paths
242
+ paths = manager.get_docs(return_paths=True)
243
+ assert len(paths) == 2
244
+ assert all(path.endswith(".md") for path in paths)
245
+
246
+ # Get specific package paths
247
+ specific_paths = manager.get_docs("testlib", return_paths=True)
248
+ assert len(specific_paths) == 1
249
+ assert specific_paths[0].endswith("README.md")
250
+
251
+ def test_get_library_docs_paths(self, manager, mock_repo_structure, mock_memory_manager):
252
+ """Test getting library documentation paths"""
253
+ mock_memory_manager.get_libs.return_value = {"testlib": {}}
254
+
255
+ paths = manager.get_library_docs_paths("testlib")
256
+ assert len(paths) == 1
257
+ assert paths[0].endswith("README.md")
258
+
259
+ def test_get_library_docs_content(self, manager, mock_repo_structure, mock_memory_manager):
260
+ """Test getting library documentation content"""
261
+ mock_memory_manager.get_libs.return_value = {"testlib": {}}
262
+
263
+ content = manager.get_library_docs_content("testlib")
264
+ assert len(content) == 1
265
+ assert "# Test Library" in content[0]
266
+
267
+ @patch('git.Repo')
268
+ def test_clone_repository_success(self, mock_git_repo, manager):
269
+ """Test successful repository cloning"""
270
+ # Repository doesn't exist
271
+ assert not os.path.exists(manager.llm_friendly_packages_dir)
272
+
273
+ result = manager._clone_repository()
274
+
275
+ assert result is True
276
+ mock_git_repo.clone_from.assert_called_once()
277
+
278
+ @patch('git.Repo')
279
+ def test_clone_repository_already_exists(self, mock_git_repo, manager):
280
+ """Test cloning when repository already exists"""
281
+ # Create the repository directory
282
+ os.makedirs(manager.llm_friendly_packages_dir)
283
+
284
+ result = manager._clone_repository()
285
+
286
+ assert result is True
287
+ mock_git_repo.clone_from.assert_not_called()
288
+
289
+ @patch('git.Repo')
290
+ def test_clone_repository_failure(self, mock_git_repo, manager):
291
+ """Test repository cloning failure"""
292
+ from git import GitCommandError
293
+ mock_git_repo.clone_from.side_effect = GitCommandError("clone", "Error")
294
+
295
+ result = manager._clone_repository()
296
+
297
+ assert result is False
298
+
299
+ @patch('git.Repo')
300
+ def test_refresh_repository_success(self, mock_git_repo, manager):
301
+ """Test successful repository refresh"""
302
+ # Create repository directory
303
+ os.makedirs(manager.llm_friendly_packages_dir)
304
+
305
+ # Mock repository
306
+ mock_repo = Mock()
307
+ mock_origin = Mock()
308
+ mock_origin.url = "https://github.com/allwefantasy/llm_friendly_packages"
309
+ mock_repo.remotes.origin = mock_origin
310
+ mock_git_repo.return_value = mock_repo
311
+
312
+ result = manager.refresh_repository()
313
+
314
+ assert result is True
315
+ mock_origin.pull.assert_called_once()
316
+
317
+ def test_refresh_repository_no_repo(self, manager):
318
+ """Test refreshing when repository doesn't exist"""
319
+ result = manager.refresh_repository()
320
+ assert result is False
321
+
322
+ @patch('git.Repo')
323
+ def test_refresh_repository_failure(self, mock_git_repo, manager):
324
+ """Test repository refresh failure"""
325
+ from git import GitCommandError
326
+
327
+ # Create repository directory
328
+ os.makedirs(manager.llm_friendly_packages_dir)
329
+
330
+ mock_repo = Mock()
331
+ mock_origin = Mock()
332
+ mock_origin.pull.side_effect = GitCommandError("pull", "Error")
333
+ mock_repo.remotes.origin = mock_origin
334
+ mock_git_repo.return_value = mock_repo
335
+
336
+ result = manager.refresh_repository()
337
+ assert result is False
338
+
339
+ def test_set_proxy_get_current(self, manager, mock_memory_manager):
340
+ """Test getting current proxy URL"""
341
+ current_proxy = manager.set_proxy()
342
+ expected_url = "https://github.com/allwefantasy/llm_friendly_packages"
343
+ assert current_proxy == expected_url
344
+ mock_memory_manager.get_config.assert_called_with("lib-proxy", expected_url)
345
+
346
+ def test_set_proxy_new_url(self, manager, mock_memory_manager):
347
+ """Test setting new proxy URL"""
348
+ new_url = "https://custom-proxy.com/repo"
349
+ result = manager.set_proxy(new_url)
350
+
351
+ assert result == new_url
352
+ mock_memory_manager.set_config.assert_called_once_with("lib-proxy", new_url)
353
+
354
+ def test_get_repository_info_exists(self, manager, mock_repo_structure):
355
+ """Test getting repository info when it exists"""
356
+ with patch('git.Repo') as mock_git_repo:
357
+ # Mock commit
358
+ mock_commit = Mock()
359
+ mock_commit.committed_datetime.isoformat.return_value = "2023-01-01T12:00:00"
360
+
361
+ mock_repo = Mock()
362
+ mock_repo.head.commit = mock_commit
363
+ mock_git_repo.return_value = mock_repo
364
+
365
+ repo_info = manager.get_repository_info()
366
+
367
+ assert repo_info.exists is True
368
+ assert repo_info.url == "https://github.com/allwefantasy/llm_friendly_packages"
369
+ assert repo_info.last_updated == "2023-01-01T12:00:00"
370
+
371
+ def test_get_repository_info_not_exists(self, manager):
372
+ """Test getting repository info when it doesn't exist"""
373
+ repo_info = manager.get_repository_info()
374
+
375
+ assert repo_info.exists is False
376
+ assert repo_info.url == "https://github.com/allwefantasy/llm_friendly_packages"
377
+ assert repo_info.last_updated is None
378
+
379
+ def test_display_added_libraries_empty(self, manager, capsys):
380
+ """Test displaying empty library list"""
381
+ manager.display_added_libraries()
382
+ captured = capsys.readouterr()
383
+ assert "No libraries added yet" in captured.out
384
+
385
+ def test_display_added_libraries_with_data(self, manager, mock_memory_manager, capsys):
386
+ """Test displaying library list with data"""
387
+ mock_memory_manager.get_libs.return_value = {"numpy": {}, "pandas": {}}
388
+
389
+ manager.display_added_libraries()
390
+ captured = capsys.readouterr()
391
+ # Console output includes library names in the table
392
+ assert "numpy" in captured.out or "pandas" in captured.out
393
+
394
+ def test_display_all_libraries_no_repo(self, manager, capsys):
395
+ """Test displaying all libraries when repository doesn't exist"""
396
+ manager.display_all_libraries()
397
+ captured = capsys.readouterr()
398
+ assert "repository does not exist" in captured.out
399
+
400
+ def test_display_library_docs_no_docs(self, manager, capsys):
401
+ """Test displaying library docs when none exist"""
402
+ manager.display_library_docs("nonexistent")
403
+ captured = capsys.readouterr()
404
+ assert "No markdown files found" in captured.out
405
+
406
+
407
+ class TestDataModels:
408
+ """Test suite for data models"""
409
+
410
+ def test_library_info_creation(self):
411
+ """Test LibraryInfo creation"""
412
+ lib_info = LibraryInfo(
413
+ domain="github.com",
414
+ username="testuser",
415
+ lib_name="testlib",
416
+ full_path="testuser/testlib",
417
+ is_added=True,
418
+ has_md_files=True
419
+ )
420
+
421
+ assert lib_info.domain == "github.com"
422
+ assert lib_info.username == "testuser"
423
+ assert lib_info.lib_name == "testlib"
424
+ assert lib_info.full_path == "testuser/testlib"
425
+ assert lib_info.is_added is True
426
+ assert lib_info.has_md_files is True
427
+
428
+ def test_library_info_defaults(self):
429
+ """Test LibraryInfo default values"""
430
+ lib_info = LibraryInfo(
431
+ domain="github.com",
432
+ username="testuser",
433
+ lib_name="testlib",
434
+ full_path="testuser/testlib",
435
+ is_added=False
436
+ )
437
+
438
+ assert lib_info.has_md_files is True # Default value
439
+
440
+ def test_package_doc_creation(self):
441
+ """Test PackageDoc creation"""
442
+ doc = PackageDoc(
443
+ file_path="/path/to/doc.md",
444
+ content="# Documentation"
445
+ )
446
+
447
+ assert doc.file_path == "/path/to/doc.md"
448
+ assert doc.content == "# Documentation"
449
+
450
+ def test_package_doc_no_content(self):
451
+ """Test PackageDoc without content"""
452
+ doc = PackageDoc(file_path="/path/to/doc.md")
453
+
454
+ assert doc.file_path == "/path/to/doc.md"
455
+ assert doc.content is None
456
+
457
+ def test_repository_info_creation(self):
458
+ """Test RepositoryInfo creation"""
459
+ repo_info = RepositoryInfo(
460
+ exists=True,
461
+ url="https://github.com/test/repo",
462
+ last_updated="2023-01-01T12:00:00"
463
+ )
464
+
465
+ assert repo_info.exists is True
466
+ assert repo_info.url == "https://github.com/test/repo"
467
+ assert repo_info.last_updated == "2023-01-01T12:00:00"
468
+
469
+ def test_repository_info_defaults(self):
470
+ """Test RepositoryInfo default values"""
471
+ repo_info = RepositoryInfo(
472
+ exists=False,
473
+ url="https://github.com/test/repo"
474
+ )
475
+
476
+ assert repo_info.exists is False
477
+ assert repo_info.url == "https://github.com/test/repo"
478
+ assert repo_info.last_updated is None
479
+
480
+
481
+ class TestIntegration:
482
+ """Integration tests"""
483
+
484
+ @pytest.fixture
485
+ def real_temp_project(self):
486
+ """Create a real temporary project for integration testing"""
487
+ temp_dir = tempfile.mkdtemp()
488
+ yield temp_dir
489
+ shutil.rmtree(temp_dir, ignore_errors=True)
490
+
491
+ def test_full_workflow_with_mocked_git(self, real_temp_project):
492
+ """Test a complete workflow with mocked git operations"""
493
+ with patch('git.Repo') as mock_git_repo:
494
+ # Create manager
495
+ manager = LLMFriendlyPackageManager(real_temp_project)
496
+
497
+ # Add a library (this will trigger repository cloning)
498
+ result = manager.add_library("test-library")
499
+ assert result is True
500
+
501
+ # Check that library is added
502
+ assert manager.has_library("test-library")
503
+ libs = manager.list_added_libraries()
504
+ assert "test-library" in libs
505
+
506
+ # Remove the library
507
+ result = manager.remove_library("test-library")
508
+ assert result is True
509
+ assert not manager.has_library("test-library")
510
+
511
+ def test_error_handling_in_docs_reading(self, real_temp_project):
512
+ """Test error handling when reading documentation files"""
513
+ manager = LLMFriendlyPackageManager(real_temp_project)
514
+
515
+ # Create a corrupted file structure
516
+ repo_dir = manager.llm_friendly_packages_dir
517
+ os.makedirs(repo_dir, exist_ok=True)
518
+
519
+ test_lib_path = os.path.join(repo_dir, "github.com", "testuser", "testlib")
520
+ os.makedirs(test_lib_path, exist_ok=True)
521
+
522
+ # Create a file with permission issues (simulate by creating a directory with same name)
523
+ bad_file_path = os.path.join(test_lib_path, "README.md")
524
+ os.makedirs(bad_file_path, exist_ok=True) # This will cause read error
525
+
526
+ # Add the library
527
+ manager.add_library("testlib")
528
+
529
+ # Try to read docs - should handle the error gracefully
530
+ docs = manager.get_library_docs_content("testlib")
531
+ assert docs == [] # Should return empty list on error
532
+
533
+
534
+ if __name__ == "__main__":
535
+ # Run tests when script is executed directly
536
+ pytest.main([__file__, "-v"])
@@ -0,0 +1,15 @@
1
+ """
2
+ Auto-Coder LLM 管理模块
3
+
4
+ 提供统一的大语言模型管理功能,包括:
5
+ - 模型配置管理
6
+ - API 密钥管理
7
+ - 模型实例化
8
+ - 价格管理
9
+ - 成本估算
10
+ """
11
+
12
+ from .manager import LLMManager
13
+ from .schema import LLMModel
14
+
15
+ __all__ = ["LLMManager", "LLMModel"]
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ LLM Error Handling Mechanism Demo Script
4
+ Demonstrates the new detailed error message functionality
5
+ """
6
+
7
+ import tempfile
8
+ from pathlib import Path
9
+ from autocoder.common.llms import LLMManager
10
+
11
+
12
+ def demo_error_handling():
13
+ """Demonstrate detailed error handling mechanism"""
14
+ print("=== LLM Error Handling Mechanism Demo ===\n")
15
+
16
+ # Use temporary directory to avoid affecting user configuration
17
+ with tempfile.TemporaryDirectory() as temp_dir:
18
+ models_json = Path(temp_dir) / "models.json"
19
+ lm = LLMManager(str(models_json))
20
+
21
+ print("1. Attempting to get non-existent model...")
22
+ try:
23
+ llm = lm.get_single_llm("non/existent", "lite")
24
+ print(" ✗ Unexpected success")
25
+ except ValueError as e:
26
+ print(f" ✓ Correctly caught error:")
27
+ print(f" {str(e)}")
28
+ print()
29
+
30
+ print("2. Attempting to get existing model without API key...")
31
+ try:
32
+ llm = lm.get_single_llm("deepseek/v3", "lite")
33
+ print(" ✗ Unexpected success")
34
+ except ValueError as e:
35
+ print(f" ✓ Correctly caught error:")
36
+ print(f" {str(e)}")
37
+ print()
38
+
39
+ print("3. Attempting to get multiple models, all unavailable...")
40
+ try:
41
+ llm = lm.get_single_llm("non/existent1,deepseek/v3,non/existent2", "lite")
42
+ print(" ✗ Unexpected success")
43
+ except ValueError as e:
44
+ print(f" ✓ Correctly caught error:")
45
+ print(f" {str(e)}")
46
+ print()
47
+
48
+ print("4. Adding a model with API key and testing...")
49
+ custom_models = [
50
+ {
51
+ "name": "demo/working",
52
+ "model_name": "demo-working-model",
53
+ "model_type": "saas/openai",
54
+ "base_url": "https://demo.api.com/v1",
55
+ "api_key": "demo-key-123"
56
+ }
57
+ ]
58
+ lm.add_models(custom_models)
59
+
60
+ try:
61
+ # This should succeed (although actual deployment would fail, but not due to key issues)
62
+ print(" ✓ Model added successfully with API key configured")
63
+ except Exception as e:
64
+ print(f" ✗ Model addition failed: {e}")
65
+ print()
66
+
67
+ print("5. Demonstrating new error messages vs old error messages...")
68
+ print(" Old error message: 'NoneType' object has no attribute 'stream_chat_oai'")
69
+ print(" New error message: Contains specific model names and failure reasons")
70
+ print()
71
+
72
+ print("=== Demo Complete ===")
73
+ print("Now users can clearly see:")
74
+ print("- Which models don't exist")
75
+ print("- Which models don't have API keys configured")
76
+ print("- Specific error reason for each model")
77
+
78
+
79
+ if __name__ == "__main__":
80
+ try:
81
+ demo_error_handling()
82
+ except Exception as e:
83
+ print(f"Error during demo: {e}")
84
+ import traceback
85
+ traceback.print_exc()