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
@@ -1,5 +1,6 @@
1
1
 
2
2
  import pytest
3
+ from collections import OrderedDict
3
4
  from typing import Dict, List, Any
4
5
 
5
6
  # 导入被测模块
@@ -8,7 +9,8 @@ from .parser import (
8
9
  parse_query,
9
10
  has_command,
10
11
  get_command_args,
11
- get_command_kwargs
12
+ get_command_kwargs,
13
+ get_query_command
12
14
  )
13
15
 
14
16
 
@@ -82,6 +84,28 @@ class TestCommandParser:
82
84
  }
83
85
  }
84
86
  assert result == expected
87
+
88
+ def test_single_command_new_params(self, parser):
89
+ """测试单个命令混合参数"""
90
+ result = parser.parse('/new "把 /Users/williamzhu/.auto-coder/async_agent/tasks/stdin_20250815101939_e9042b6c 中未commit变更合并回来"')
91
+ expected = {
92
+ "new": {
93
+ "args": ['把 /Users/williamzhu/.auto-coder/async_agent/tasks/stdin_20250815101939_e9042b6c 中未commit变更合并回来'],
94
+ "kwargs": {}
95
+ }
96
+ }
97
+ assert result == expected
98
+
99
+ def test_single_command_async_params(self, parser):
100
+ """测试单个命令混合参数"""
101
+ result = parser.parse("/async \"/list @./src/agent.ts 中,while 循环里有loop call limit 限制,当前会发出一个 emitEvent 事件,同时也需要发出一个渲染事件(opts.render方法)\"")
102
+ expected = {
103
+ "async": {
104
+ "args": ['/list @./src/agent.ts 中,while 循环里有loop call limit 限制,当前会发出一个 emitEvent 事件,同时也需要发出一个渲染事件(opts.render方法)'],
105
+ "kwargs": {}
106
+ }
107
+ }
108
+ assert result == expected
85
109
 
86
110
  def test_quoted_args_double_quotes(self, parser):
87
111
  """测试双引号参数"""
@@ -153,6 +177,24 @@ class TestCommandParser:
153
177
  }
154
178
  assert result == expected
155
179
 
180
+ def test_command_order_preservation(self, parser):
181
+ """测试命令顺序保持"""
182
+ result = parser.parse("/third /first /second arg1 /fourth key=value")
183
+
184
+ # 验证返回的是OrderedDict
185
+ assert isinstance(result, OrderedDict)
186
+
187
+ # 验证命令顺序
188
+ command_order = list(result.keys())
189
+ expected_order = ["third", "first", "second", "fourth"]
190
+ assert command_order == expected_order
191
+
192
+ # 验证内容正确性
193
+ assert result["third"]["args"] == []
194
+ assert result["first"]["args"] == []
195
+ assert result["second"]["args"] == ["arg1"]
196
+ assert result["fourth"]["kwargs"] == {"key": "value"}
197
+
156
198
  def test_path_not_recognized_as_command(self, parser):
157
199
  """测试路径不被识别为命令"""
158
200
  result = parser.parse("/add /path/to/file.txt /config model=gpt-4")
@@ -243,6 +285,46 @@ class TestCommandParser:
243
285
  }
244
286
  }
245
287
  assert result == expected
288
+
289
+ def test_auto_new_complex_scenario(self, parser):
290
+ """测试复杂的自动化场景:/auto /new 运行使用交互式方式运行 auto-coder.chat 然后在里面运行 /rules /list"""
291
+ query = "/auto /new 运行使用交互式方式运行 auto-coder.chat 然后在里面运行 /rules /list"
292
+ result = parser.parse(query)
293
+ expected = {
294
+ "auto": {
295
+ "args": [],
296
+ "kwargs": {}
297
+ },
298
+ "new": {
299
+ "args": ["运行使用交互式方式运行", "auto-coder.chat", "然后在里面运行"],
300
+ "kwargs": {}
301
+ },
302
+ "rules": {
303
+ "args": [],
304
+ "kwargs": {}
305
+ },
306
+ "list": {
307
+ "args": [],
308
+ "kwargs": {}
309
+ }
310
+ }
311
+ assert result == expected
312
+
313
+ def test_auto_new_complex_scenario2(self, parser):
314
+ """测试复杂的自动化场景:/auto /new 运行使用交互式方式运行 auto-coder.chat 然后在里面运行 /rules /list"""
315
+ query = '/auto /new "运行使用交互式方式运行 auto-coder.chat 然后在里面运行 /rules /list"'
316
+ result = parser.parse(query)
317
+ expected = {
318
+ "auto": {
319
+ "args": [],
320
+ "kwargs": {}
321
+ },
322
+ "new": {
323
+ "args": ["运行使用交互式方式运行 auto-coder.chat 然后在里面运行 /rules /list"],
324
+ "kwargs": {}
325
+ }
326
+ }
327
+ assert result == expected
246
328
 
247
329
 
248
330
  class TestConvenienceFunctions:
@@ -251,6 +333,10 @@ class TestConvenienceFunctions:
251
333
  def test_parse_query_function(self):
252
334
  """测试parse_query函数"""
253
335
  result = parse_query("/add file1.txt mode=fast")
336
+
337
+ # 验证返回的是OrderedDict
338
+ assert isinstance(result, OrderedDict)
339
+
254
340
  expected = {
255
341
  "add": {
256
342
  "args": ["file1.txt"],
@@ -426,9 +512,12 @@ class TestErrorHandling:
426
512
  """测试命令中的特殊字符"""
427
513
  parser = CommandParser()
428
514
 
429
- # 命令名只能包含单词字符,所以这些不会被识别为命令
515
+ # 命令名可以包含单词字符和连字符,但不能包含点号
430
516
  result = parser.parse("/test-command /test.command")
431
- assert result == {}
517
+ expected = OrderedDict({
518
+ 'test-command': {'args': ['/test.command'], 'kwargs': {}}
519
+ })
520
+ assert result == expected
432
521
 
433
522
  def test_whitespace_handling(self):
434
523
  """测试空白字符处理"""
@@ -460,19 +549,6 @@ class TestErrorHandling:
460
549
  }
461
550
  assert result == expected
462
551
 
463
- def test__command_with_path(self, parser):
464
- """测试单个命令混合参数"""
465
- result = parser.parse('/command "tdd/hello.md" name="威廉"')
466
- expected = {
467
- "command": {
468
- "args": ["tdd/hello.md"],
469
- "kwargs": {
470
- "name": "威廉"
471
- }
472
- }
473
- }
474
- assert result == expected
475
-
476
552
 
477
553
  # 参数化测试用例
478
554
  @pytest.mark.parametrize("query,expected_commands", [
@@ -511,6 +587,155 @@ def test_get_kwargs_parametrized(query, command, expected_kwargs):
511
587
  assert get_command_kwargs(query, command) == expected_kwargs
512
588
 
513
589
 
590
+ class TestQueryCommand:
591
+ """测试 QueryCommand 类和 get_query_command 函数"""
592
+
593
+ def test_basic_query_command(self):
594
+ """测试基本的 QueryCommand 功能"""
595
+ query = "/model gpt-4 /temperature 0.7"
596
+ v = get_query_command(query)
597
+
598
+ assert v.model == "gpt-4"
599
+ assert v.temperature == "0.7"
600
+ assert v.query == ""
601
+
602
+ def test_query_command_with_sub_commands(self):
603
+ """测试带子命令的 QueryCommand"""
604
+ query = "/async /model gpt-4 /task-prefix mytask hello world"
605
+ v = get_query_command(query, sub_commands=["model", "task-prefix"])
606
+
607
+ assert v.model == "gpt-4"
608
+ assert v.task_prefix == "mytask"
609
+ assert v.query == "hello world"
610
+
611
+ def test_query_command_hyphen_to_underscore(self):
612
+ """测试连字符自动转换为下划线"""
613
+ query = "/task-prefix mytask /api-key secret123"
614
+ v = get_query_command(query)
615
+
616
+ # 可以用下划线访问
617
+ assert v.task_prefix == "mytask"
618
+ assert v.api_key == "secret123"
619
+
620
+ def test_query_command_multiple_args(self):
621
+ """测试多个参数的处理"""
622
+ query = "/async /model gpt-4 /task-prefix mytask arg1 arg2 arg3"
623
+ v = get_query_command(query, sub_commands=["model", "task-prefix"])
624
+
625
+ assert v.model == "gpt-4"
626
+ assert v.task_prefix == "mytask"
627
+ assert v.query == "arg1 arg2 arg3"
628
+
629
+ def test_query_command_no_special_handling(self):
630
+ """测试不进行特殊处理的情况"""
631
+ query = "/model gpt-4 extra /task-prefix mytask arg1 arg2"
632
+ v = get_query_command(query, sub_commands=None)
633
+
634
+ # 没有指定sub_commands,所以不会特殊处理
635
+ assert v.model == ["gpt-4", "extra"]
636
+ assert v.task_prefix == ["mytask", "arg1", "arg2"]
637
+ assert v.query == ""
638
+
639
+ def test_query_command_with_kwargs(self):
640
+ """测试带键值对参数的命令"""
641
+ query = "/config model=gpt-4 temperature=0.7"
642
+ v = get_query_command(query)
643
+
644
+ config = v.config
645
+ assert isinstance(config, dict)
646
+ assert config["model"] == "gpt-4"
647
+ assert config["temperature"] == "0.7"
648
+
649
+ def test_query_command_mixed_args_kwargs(self):
650
+ """测试混合参数的命令"""
651
+ query = "/deploy myapp env=prod version=1.0"
652
+ v = get_query_command(query)
653
+
654
+ # deploy 命令有位置参数和键值对参数
655
+ # 当有kwargs时,返回kwargs
656
+ deploy_info = v.get_command_info("deploy")
657
+ assert deploy_info["args"] == ["myapp"]
658
+ assert deploy_info["kwargs"] == {"env": "prod", "version": "1.0"}
659
+
660
+ def test_query_command_has_command(self):
661
+ """测试 has_command 方法"""
662
+ query = "/model gpt-4 /task-prefix mytask"
663
+ v = get_query_command(query)
664
+
665
+ assert v.has_command("model") == True
666
+ assert v.has_command("task-prefix") == True
667
+ assert v.has_command("task_prefix") == True # 也可以用下划线形式
668
+ assert v.has_command("nonexistent") == False
669
+
670
+ def test_query_command_get_all_commands(self):
671
+ """测试 get_all_commands 方法"""
672
+ query = "/first /second /third"
673
+ v = get_query_command(query)
674
+
675
+ commands = v.get_all_commands()
676
+ assert commands == ["first", "second", "third"]
677
+
678
+ def test_query_command_nonexistent_attribute(self):
679
+ """测试访问不存在的属性"""
680
+ query = "/model gpt-4"
681
+ v = get_query_command(query)
682
+
683
+ assert v.model == "gpt-4"
684
+ assert v.nonexistent is None
685
+
686
+ def test_query_command_empty_command(self):
687
+ """测试空参数的命令"""
688
+ query = "/start /stop /restart"
689
+ v = get_query_command(query)
690
+
691
+ assert v.start == ""
692
+ assert v.stop == ""
693
+ assert v.restart == ""
694
+
695
+ def test_query_command_complex_scenario(self):
696
+ """测试复杂场景"""
697
+ query = '/async /model gpt-4-turbo /task-prefix analysis "Process the following data" with multiple words'
698
+ v = get_query_command(query, sub_commands=["model", "task-prefix"])
699
+
700
+ assert v.model == "gpt-4-turbo"
701
+ assert v.task_prefix == "analysis" # 第一个参数
702
+ assert v.query == 'Process the following data with multiple words' # 剩余参数
703
+
704
+ def test_query_command_last_command_not_in_list(self):
705
+ """测试最后一个命令不在子命令列表中"""
706
+ query = "/model gpt-4 /other command /final arg1 arg2 arg3"
707
+ v = get_query_command(query, sub_commands=["model"])
708
+
709
+ # model 是子命令但不是最后一个,所以保持原样
710
+ assert v.model == "gpt-4"
711
+ # other 和 final 不在子命令列表中,保持原样
712
+ assert v.other == "command"
713
+ assert v.final == ["arg1", "arg2", "arg3"]
714
+ assert v.query == ""
715
+
716
+ def test_query_command_disable_last_takes_rest(self):
717
+ """测试禁用 last_command_takes_rest"""
718
+ query = "/model gpt-4 /task-prefix mytask arg1 arg2"
719
+ v = get_query_command(query,
720
+ sub_commands=["model", "task-prefix"],
721
+ last_command_takes_rest=False)
722
+
723
+ # 禁用了特殊处理,所以所有参数都保留
724
+ assert v.model == "gpt-4"
725
+ assert v.task_prefix == ["mytask", "arg1", "arg2"]
726
+ assert v.query == ""
727
+
728
+ def test_query_command_repr(self):
729
+ """测试 __repr__ 方法"""
730
+ query = "/model gpt-4 /task-prefix mytask hello"
731
+ v = get_query_command(query, sub_commands=["task-prefix"])
732
+
733
+ repr_str = repr(v)
734
+ assert "QueryCommand" in repr_str
735
+ assert "model" in repr_str
736
+ assert "task-prefix" in repr_str
737
+
738
+
514
739
  if __name__ == "__main__":
515
740
  # 可以直接运行此文件进行测试
516
741
  pytest.main([__file__, "-v"])
@@ -0,0 +1,342 @@
1
+ import pytest
2
+ from typing import List, Dict, Any
3
+
4
+ from .config import (
5
+ ConfigBuilder,
6
+ create_config
7
+ )
8
+
9
+ from .typed_parser import (
10
+ ParsedCommand,
11
+ TypedCommandParser,
12
+ parse_typed_query
13
+ )
14
+
15
+
16
+ class TestTypedCommandParser:
17
+ """测试 TypedCommandParser 类"""
18
+
19
+ def test_basic_typed_parsing(self):
20
+ """测试基本的类型化解析"""
21
+ config = (create_config()
22
+ .command("model")
23
+ .positional("name", required=True)
24
+ .command("config")
25
+ .keyword("temperature", type=float)
26
+ .keyword("max_tokens", type=int)
27
+ .build()
28
+ )
29
+
30
+ parser = TypedCommandParser(config)
31
+ result = parser.parse_typed(
32
+ "/model gpt-4 /config temperature=0.8 max_tokens=100")
33
+
34
+ assert "model" in result
35
+ assert result["model"].args == ["gpt-4"]
36
+ assert result["model"].is_valid
37
+
38
+ assert "config" in result
39
+ assert result["config"].kwargs["temperature"] == 0.8 # 转换为float
40
+ assert result["config"].kwargs["max_tokens"] == 100 # 转换为int
41
+ assert result["config"].is_valid
42
+
43
+ def test_typed_parsing_with_validation_errors(self):
44
+ """测试带验证错误的类型化解析"""
45
+ config = (create_config()
46
+ .command("model")
47
+ .positional("name", required=True, choices=["gpt-3.5", "gpt-4"])
48
+ .build()
49
+ )
50
+
51
+ parser = TypedCommandParser(config)
52
+ result = parser.parse_typed("/model gpt-5")
53
+
54
+ assert "model" in result
55
+ assert not result["model"].is_valid
56
+ assert len(result["model"].errors) > 0
57
+
58
+ def test_typed_parsing_with_defaults(self):
59
+ """测试带默认值的类型化解析"""
60
+ config = (create_config()
61
+ .command("config")
62
+ .keyword("temperature", type=float, default=0.7)
63
+ .keyword("max_tokens", type=int, default=100)
64
+ .build()
65
+ )
66
+
67
+ parser = TypedCommandParser(config)
68
+ result = parser.parse_typed("/config temperature=0.9")
69
+
70
+ assert result["config"].kwargs["temperature"] == 0.9
71
+ assert result["config"].kwargs["max_tokens"] == 100 # 使用默认值
72
+
73
+ def test_typed_parsing_with_remainder(self):
74
+ """测试收集剩余参数的类型化解析"""
75
+ config = (create_config()
76
+ .command("task")
77
+ .positional("prefix", required=True)
78
+ .collect_remainder("query")
79
+ .build()
80
+ )
81
+
82
+ parser = TypedCommandParser(config)
83
+ result = parser.parse_typed("/task mytask this is the query")
84
+
85
+ assert result["task"].args == ["mytask"]
86
+ assert result["task"].remainder == "this is the query"
87
+
88
+ def test_typed_parsing_strict_mode(self):
89
+ """测试严格模式"""
90
+ config = (create_config()
91
+ .strict(True)
92
+ .command("known")
93
+ .build()
94
+ )
95
+
96
+ parser = TypedCommandParser(config)
97
+ result = parser.parse_typed("/known /unknown")
98
+
99
+ assert result["known"].is_valid
100
+ assert not result["unknown"].is_valid
101
+ assert "Unknown command" in result["unknown"].errors[0]
102
+
103
+ def test_bool_type_conversion(self):
104
+ """测试布尔类型转换"""
105
+ config = (create_config()
106
+ .command("flags")
107
+ .keyword("verbose", type=bool)
108
+ .keyword("debug", type=bool)
109
+ .build()
110
+ )
111
+
112
+ parser = TypedCommandParser(config)
113
+
114
+ # 测试各种布尔值表示
115
+ result = parser.parse_typed("/flags verbose=true debug=false")
116
+ assert result["flags"].kwargs["verbose"] is True
117
+ assert result["flags"].kwargs["debug"] is False
118
+
119
+ result = parser.parse_typed("/flags verbose=1 debug=0")
120
+ assert result["flags"].kwargs["verbose"] is True
121
+ assert result["flags"].kwargs["debug"] is False
122
+
123
+ result = parser.parse_typed("/flags verbose=yes debug=no")
124
+ assert result["flags"].kwargs["verbose"] is True
125
+ assert result["flags"].kwargs["debug"] is False
126
+
127
+
128
+ class TestTypedQueryCommand:
129
+ """测试 TypedQueryCommand 类"""
130
+
131
+ def test_basic_typed_query_command(self):
132
+ """测试基本的类型化查询命令"""
133
+ config = (create_config()
134
+ .command("model")
135
+ .positional("name", required=True)
136
+ .command("temperature")
137
+ # value 名字比较特殊,作为位置参数,可以直接通过 result.temperature 访问
138
+ .positional("value", type=float)
139
+ .build()
140
+ )
141
+
142
+ result = parse_typed_query("/model gpt-4 /temperature 0.8", config)
143
+
144
+ assert result.model.name == "gpt-4"
145
+ assert result.temperature == 0.8
146
+ assert isinstance(result.temperature, float)
147
+
148
+ def test_typed_query_command_with_remainder(self):
149
+ """测试带剩余参数的类型化查询命令"""
150
+ config = (create_config()
151
+ .command("task")
152
+ .positional("prefix", required=True)
153
+ .collect_remainder("query")
154
+ .build()
155
+ )
156
+
157
+ result = parse_typed_query("/task mytask this is the query", config)
158
+
159
+ assert result.task.prefix == "mytask"
160
+ assert result.task.query == "this is the query"
161
+
162
+ def test_typed_query_command_validation(self):
163
+ """测试类型化查询命令的验证"""
164
+ config = (create_config()
165
+ .command("model")
166
+ .positional("name", required=True, choices=["gpt-3.5", "gpt-4"])
167
+ .build()
168
+ )
169
+
170
+ result = parse_typed_query("/model gpt-5", config)
171
+
172
+ assert not result.is_valid()
173
+ errors = result.get_errors()
174
+ assert "model" in errors
175
+
176
+ def test_typed_query_command_get_command(self):
177
+ """测试获取解析后的命令对象"""
178
+ config = (create_config()
179
+ .command("config")
180
+ .keyword("temperature", type=float)
181
+ .build()
182
+ )
183
+
184
+ result = parse_typed_query("/config temperature=0.8", config)
185
+
186
+ parsed_cmd = result.get_command("config")
187
+ assert isinstance(parsed_cmd, ParsedCommand)
188
+ assert parsed_cmd.name == "config"
189
+ assert parsed_cmd.kwargs["temperature"] == 0.8
190
+
191
+ def test_typed_query_command_hyphen_conversion(self):
192
+ """测试连字符转换"""
193
+ config = (create_config()
194
+ .command("task-prefix")
195
+ # value 名字比较特殊,作为位置参数,可以直接通过 result.task_prefix 访问
196
+ .positional("value")
197
+ .build()
198
+ )
199
+
200
+ result = parse_typed_query("/task-prefix mytask", config)
201
+
202
+ # 可以用下划线访问
203
+ assert result.task_prefix == "mytask"
204
+ assert result.has_command("task-prefix")
205
+ assert result.has_command("task_prefix")
206
+
207
+
208
+ class TestIntegrationScenarios:
209
+ """集成测试场景"""
210
+ def test_validation_and_error_reporting(self):
211
+ """测试验证和错误报告"""
212
+ config = (create_config()
213
+ .strict(True) # 严格模式
214
+ .command("deploy")
215
+ .positional("app", required=True)
216
+ .keyword("env", required=True, choices=["dev", "staging", "prod"])
217
+ .keyword("version", required=True)
218
+ .build()
219
+ )
220
+
221
+ # 缺少必需参数
222
+ result = parse_typed_query("/deploy myapp", config)
223
+ assert not result.is_valid()
224
+ errors = result.get_errors()
225
+ assert "deploy" in errors
226
+ assert any("env" in e for e in errors["deploy"])
227
+
228
+ # 无效的选项值
229
+ result = parse_typed_query(
230
+ "/deploy myapp env=test version=1.0", config)
231
+ assert not result.is_valid()
232
+ errors = result.get_errors()
233
+ assert any("must be one of" in e for e in errors["deploy"])
234
+
235
+ # 未知命令(严格模式)
236
+ result = parse_typed_query("/unknown", config)
237
+ assert not result.is_valid()
238
+ errors = result.get_errors()
239
+ assert "unknown" in errors
240
+
241
+
242
+ class TestCommandLevelRemainder:
243
+ """测试命令级别的剩余参数收集"""
244
+ def test_async_command_scenario(self):
245
+ global_config = (create_config()
246
+ .collect_remainder("query")
247
+ .command("async")
248
+ .max_args(0)
249
+ .command("model")
250
+ # 用 name 也可以;用 "value" 可直接 result.model 返回值
251
+ .positional("value", required=True)
252
+ .max_args(1)
253
+ .command("loop")
254
+ .positional("value", type=int)
255
+ .command("name")
256
+ .max_args(1)
257
+ .build()
258
+ )
259
+
260
+ result = parse_typed_query(
261
+ "/async /model gpt-4 /loop 3 /name task-01 analysis Process the data", global_config)
262
+ assert result.model == "gpt-4"
263
+ assert result.loop == 3
264
+ assert result.name == "task-01"
265
+ assert result.query == "analysis Process the data"
266
+
267
+ result = parse_typed_query(
268
+ "/async /model gpt-4 /name task-01 /loop 3 analysis Process the data", global_config)
269
+ assert result.model == "gpt-4"
270
+ assert result.loop == 3
271
+ assert result.name == "task-01"
272
+ assert result.query == "analysis Process the data"
273
+
274
+ result = parse_typed_query(
275
+ "/async /name task-01 /model gpt-4 /loop 3 analysis Process the data", global_config)
276
+ assert result.model == "gpt-4"
277
+ assert result.loop == 3
278
+ assert result.name == "task-01"
279
+ assert result.query == "analysis Process the data"
280
+
281
+ def test_quoted_string_scenario(self):
282
+ global_config = (create_config()
283
+ .collect_remainder("query")
284
+ .command("async")
285
+ .max_args(0)
286
+ .command("model")
287
+ # 用 name 也可以;用 "value" 可直接 result.model 返回值
288
+ .positional("value", required=True)
289
+ .max_args(1)
290
+ .command("loop")
291
+ .positional("value", type=int)
292
+ .command("name")
293
+ .max_args(1)
294
+ .command("wow")
295
+ .keyword("name", type=str)
296
+ .keyword("x", type=str)
297
+ .build()
298
+ )
299
+
300
+ result = parse_typed_query(
301
+ "/async /model gpt-4 /loop 3 /name task-01 \"analysis Process the data\"", global_config)
302
+ assert result.model == "gpt-4"
303
+ assert result.loop == 3
304
+ assert result.name == "task-01"
305
+ assert result.query == "analysis Process the data"
306
+
307
+ result = parse_typed_query(
308
+ "/async /model gpt-4 /name task-01 /loop 3 \"analysis Process the data\"", global_config)
309
+ assert result.model == "gpt-4"
310
+ assert result.loop == 3
311
+ assert result.name == "task-01"
312
+ assert result.query == "analysis Process the data"
313
+
314
+ result = parse_typed_query(
315
+ "/async /name task-01 /model gpt-4 /loop 3 \"\"\"analysis Process the data\"\"\"", global_config)
316
+ assert result.model == "gpt-4"
317
+ assert result.loop == 3
318
+ assert result.name == "task-01"
319
+ assert result.query == "analysis Process the data"
320
+
321
+
322
+ result = parse_typed_query(
323
+ "/async /name task-01 /model gpt-4 /wow name=test x=\"analysis2 Process the data\" /loop 3 \"\"\"analysis Process the data\"\"\"", global_config)
324
+ assert result.model == "gpt-4"
325
+ assert result.loop == 3
326
+ assert result.name == "task-01"
327
+ assert result.query == "analysis Process the data"
328
+ assert result.wow.name == "test"
329
+ assert result.wow.x == "analysis2 Process the data"
330
+
331
+
332
+ result = parse_typed_query(
333
+ "/async /name task-01 /model gpt-4 /wow name=test x=\"\"\"analysis2 \Process the data\"\"\" /loop 3 \"\"\"analysis Process the data\"\"\"", global_config)
334
+ assert result.model == "gpt-4"
335
+ assert result.loop == 3
336
+ assert result.name == "task-01"
337
+ assert result.query == "analysis Process the data"
338
+ assert result.wow.name == "test"
339
+ assert result.wow.x == "analysis2 \Process the data"
340
+
341
+ if __name__ == "__main__":
342
+ pytest.main([__file__, "-v"])