auto-coder 1.0.0__py3-none-any.whl → 2.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of auto-coder might be problematic. Click here for more details.

Files changed (574) 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-1.0.0.dist-info → auto_coder-2.0.0.dist-info}/WHEEL +1 -1
  5. {auto_coder-1.0.0.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 +24 -3
  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 +970 -2345
  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 +988 -398
  28. autocoder/chat_auto_coder_lang.py +23 -732
  29. autocoder/commands/auto_command.py +25 -8
  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/git_utils.py +44 -8
  119. autocoder/common/global_cancel.py +15 -6
  120. autocoder/common/ignorefiles/test_ignore_file_utils.py +1 -1
  121. autocoder/common/international/__init__.py +31 -0
  122. autocoder/common/international/demo_international.py +92 -0
  123. autocoder/common/international/message_manager.py +157 -0
  124. autocoder/common/international/messages/__init__.py +56 -0
  125. autocoder/common/international/messages/async_command_messages.py +507 -0
  126. autocoder/common/international/messages/auto_coder_messages.py +2208 -0
  127. autocoder/common/international/messages/chat_auto_coder_messages.py +1547 -0
  128. autocoder/common/international/messages/command_help_messages.py +986 -0
  129. autocoder/common/international/messages/conversation_command_messages.py +191 -0
  130. autocoder/common/international/messages/git_helper_plugin_messages.py +159 -0
  131. autocoder/common/international/messages/queue_command_messages.py +751 -0
  132. autocoder/common/international/messages/rules_command_messages.py +77 -0
  133. autocoder/common/international/messages/sdk_messages.py +1707 -0
  134. autocoder/common/international/messages/token_helper_plugin_messages.py +361 -0
  135. autocoder/common/international/messages/tool_display_messages.py +1212 -0
  136. autocoder/common/international/messages/workflow_exception_messages.py +473 -0
  137. autocoder/common/international/test_international.py +612 -0
  138. autocoder/common/linter_core/__init__.py +28 -0
  139. autocoder/common/linter_core/base_linter.py +61 -0
  140. autocoder/common/linter_core/config_loader.py +271 -0
  141. autocoder/common/linter_core/formatters/__init__.py +0 -0
  142. autocoder/common/linter_core/formatters/base_formatter.py +38 -0
  143. autocoder/common/linter_core/formatters/raw_formatter.py +17 -0
  144. autocoder/common/linter_core/linter.py +166 -0
  145. autocoder/common/linter_core/linter_factory.py +216 -0
  146. autocoder/common/linter_core/linter_manager.py +333 -0
  147. autocoder/common/linter_core/linters/__init__.py +9 -0
  148. autocoder/common/linter_core/linters/java_linter.py +342 -0
  149. autocoder/common/linter_core/linters/python_linter.py +115 -0
  150. autocoder/common/linter_core/linters/typescript_linter.py +119 -0
  151. autocoder/common/linter_core/models/__init__.py +7 -0
  152. autocoder/common/linter_core/models/lint_result.py +91 -0
  153. autocoder/common/linter_core/models.py +33 -0
  154. autocoder/common/linter_core/tests/__init__.py +3 -0
  155. autocoder/common/linter_core/tests/test_config_loader.py +323 -0
  156. autocoder/common/linter_core/tests/test_config_loading.py +308 -0
  157. autocoder/common/linter_core/tests/test_factory_manager.py +234 -0
  158. autocoder/common/linter_core/tests/test_formatters.py +147 -0
  159. autocoder/common/linter_core/tests/test_integration.py +317 -0
  160. autocoder/common/linter_core/tests/test_java_linter.py +496 -0
  161. autocoder/common/linter_core/tests/test_linters.py +265 -0
  162. autocoder/common/linter_core/tests/test_models.py +81 -0
  163. autocoder/common/linter_core/tests/verify_config_loading.py +296 -0
  164. autocoder/common/linter_core/tests/verify_fixes.py +183 -0
  165. autocoder/common/llm_friendly_package/__init__.py +31 -0
  166. autocoder/common/llm_friendly_package/base_manager.py +102 -0
  167. autocoder/common/llm_friendly_package/docs_manager.py +121 -0
  168. autocoder/common/llm_friendly_package/library_manager.py +171 -0
  169. autocoder/common/{llm_friendly_package.py → llm_friendly_package/main_manager.py} +204 -231
  170. autocoder/common/llm_friendly_package/models.py +40 -0
  171. autocoder/common/llm_friendly_package/test_llm_friendly_package.py +536 -0
  172. autocoder/common/llms/__init__.py +15 -0
  173. autocoder/common/llms/demo_error_handling.py +85 -0
  174. autocoder/common/llms/factory.py +142 -0
  175. autocoder/common/llms/manager.py +264 -0
  176. autocoder/common/llms/pricing.py +121 -0
  177. autocoder/common/llms/registry.py +288 -0
  178. autocoder/common/llms/schema.py +77 -0
  179. autocoder/common/llms/simple_demo.py +45 -0
  180. autocoder/common/llms/test_quick_model.py +116 -0
  181. autocoder/common/llms/test_remove_functionality.py +182 -0
  182. autocoder/common/llms/tests/__init__.py +1 -0
  183. autocoder/common/llms/tests/test_manager.py +330 -0
  184. autocoder/common/llms/tests/test_registry.py +364 -0
  185. autocoder/common/mcp_tools/__init__.py +62 -0
  186. autocoder/common/{mcp_tools.py → mcp_tools/executor.py} +49 -40
  187. autocoder/common/{mcp_hub.py → mcp_tools/hub.py} +42 -68
  188. autocoder/common/{mcp_server_install.py → mcp_tools/installer.py} +16 -28
  189. autocoder/common/{mcp_server.py → mcp_tools/server.py} +176 -48
  190. autocoder/common/mcp_tools/test_keyboard_interrupt.py +93 -0
  191. autocoder/common/mcp_tools/test_mcp_tools.py +391 -0
  192. autocoder/common/{mcp_server_types.py → mcp_tools/types.py} +121 -48
  193. autocoder/common/mcp_tools/verify_functionality.py +202 -0
  194. autocoder/common/model_speed_tester.py +32 -26
  195. autocoder/common/priority_directory_finder/__init__.py +142 -0
  196. autocoder/common/priority_directory_finder/examples.py +230 -0
  197. autocoder/common/priority_directory_finder/finder.py +283 -0
  198. autocoder/common/priority_directory_finder/models.py +236 -0
  199. autocoder/common/priority_directory_finder/test_priority_directory_finder.py +431 -0
  200. autocoder/common/project_scanner/__init__.py +18 -0
  201. autocoder/common/project_scanner/compat.py +77 -0
  202. autocoder/common/project_scanner/scanner.py +436 -0
  203. autocoder/common/project_tracker/__init__.py +27 -0
  204. autocoder/common/project_tracker/api.py +228 -0
  205. autocoder/common/project_tracker/demo.py +272 -0
  206. autocoder/common/project_tracker/tracker.py +487 -0
  207. autocoder/common/project_tracker/types.py +53 -0
  208. autocoder/common/pruner/__init__.py +67 -0
  209. autocoder/common/pruner/agentic_conversation_pruner.py +651 -102
  210. autocoder/common/pruner/conversation_message_ids_api.py +386 -0
  211. autocoder/common/pruner/conversation_message_ids_manager.py +347 -0
  212. autocoder/common/pruner/conversation_message_ids_pruner.py +473 -0
  213. autocoder/common/pruner/conversation_normalizer.py +347 -0
  214. autocoder/common/pruner/conversation_pruner.py +26 -6
  215. autocoder/common/pruner/test_agentic_conversation_pruner.py +554 -112
  216. autocoder/common/pruner/test_conversation_normalizer.py +502 -0
  217. autocoder/common/pruner/test_tool_content_detector.py +324 -0
  218. autocoder/common/pruner/tool_content_detector.py +227 -0
  219. autocoder/common/pruner/tools/__init__.py +18 -0
  220. autocoder/common/pruner/tools/query_message_ids.py +264 -0
  221. autocoder/common/pruner/tools/test_agentic_pruning_logic.py +432 -0
  222. autocoder/common/pruner/tools/test_message_ids_pruning_only.py +192 -0
  223. autocoder/common/pull_requests/__init__.py +9 -1
  224. autocoder/common/pull_requests/utils.py +122 -1
  225. autocoder/common/rag_manager/rag_manager.py +36 -40
  226. autocoder/common/rulefiles/__init__.py +53 -1
  227. autocoder/common/rulefiles/api.py +250 -0
  228. autocoder/common/rulefiles/core/__init__.py +14 -0
  229. autocoder/common/rulefiles/core/manager.py +241 -0
  230. autocoder/common/rulefiles/core/selector.py +805 -0
  231. autocoder/common/rulefiles/models/__init__.py +20 -0
  232. autocoder/common/rulefiles/models/index.py +16 -0
  233. autocoder/common/rulefiles/models/init_rule.py +18 -0
  234. autocoder/common/rulefiles/models/rule_file.py +18 -0
  235. autocoder/common/rulefiles/models/rule_relevance.py +14 -0
  236. autocoder/common/rulefiles/models/summary.py +16 -0
  237. autocoder/common/rulefiles/test_rulefiles.py +776 -0
  238. autocoder/common/rulefiles/utils/__init__.py +34 -0
  239. autocoder/common/rulefiles/utils/monitor.py +86 -0
  240. autocoder/common/rulefiles/utils/parser.py +230 -0
  241. autocoder/common/save_formatted_log.py +67 -10
  242. autocoder/common/search_replace.py +8 -1
  243. autocoder/common/search_replace_patch/__init__.py +24 -0
  244. autocoder/common/search_replace_patch/base.py +115 -0
  245. autocoder/common/search_replace_patch/manager.py +248 -0
  246. autocoder/common/search_replace_patch/patch_replacer.py +304 -0
  247. autocoder/common/search_replace_patch/similarity_replacer.py +306 -0
  248. autocoder/common/search_replace_patch/string_replacer.py +181 -0
  249. autocoder/common/search_replace_patch/tests/__init__.py +3 -0
  250. autocoder/common/search_replace_patch/tests/run_tests.py +126 -0
  251. autocoder/common/search_replace_patch/tests/test_base.py +188 -0
  252. autocoder/common/search_replace_patch/tests/test_empty_line_insert.py +233 -0
  253. autocoder/common/search_replace_patch/tests/test_integration.py +389 -0
  254. autocoder/common/search_replace_patch/tests/test_manager.py +351 -0
  255. autocoder/common/search_replace_patch/tests/test_patch_replacer.py +316 -0
  256. autocoder/common/search_replace_patch/tests/test_regex_replacer.py +306 -0
  257. autocoder/common/search_replace_patch/tests/test_similarity_replacer.py +384 -0
  258. autocoder/common/shell_commands/__init__.py +197 -0
  259. autocoder/common/shell_commands/background_process_notifier.py +346 -0
  260. autocoder/common/shell_commands/command_executor.py +1127 -0
  261. autocoder/common/shell_commands/error_recovery.py +541 -0
  262. autocoder/common/shell_commands/exceptions.py +120 -0
  263. autocoder/common/shell_commands/interactive_executor.py +476 -0
  264. autocoder/common/shell_commands/interactive_pexpect_process.py +623 -0
  265. autocoder/common/shell_commands/interactive_process.py +744 -0
  266. autocoder/common/shell_commands/interactive_session_manager.py +1014 -0
  267. autocoder/common/shell_commands/monitoring.py +529 -0
  268. autocoder/common/shell_commands/process_cleanup.py +386 -0
  269. autocoder/common/shell_commands/process_manager.py +606 -0
  270. autocoder/common/shell_commands/test_interactive_pexpect_process.py +281 -0
  271. autocoder/common/shell_commands/tests/__init__.py +6 -0
  272. autocoder/common/shell_commands/tests/conftest.py +118 -0
  273. autocoder/common/shell_commands/tests/test_background_process_notifier.py +703 -0
  274. autocoder/common/shell_commands/tests/test_command_executor.py +448 -0
  275. autocoder/common/shell_commands/tests/test_error_recovery.py +305 -0
  276. autocoder/common/shell_commands/tests/test_exceptions.py +299 -0
  277. autocoder/common/shell_commands/tests/test_execute_batch.py +588 -0
  278. autocoder/common/shell_commands/tests/test_indented_batch_commands.py +244 -0
  279. autocoder/common/shell_commands/tests/test_integration.py +664 -0
  280. autocoder/common/shell_commands/tests/test_monitoring.py +546 -0
  281. autocoder/common/shell_commands/tests/test_performance.py +632 -0
  282. autocoder/common/shell_commands/tests/test_process_cleanup.py +397 -0
  283. autocoder/common/shell_commands/tests/test_process_manager.py +606 -0
  284. autocoder/common/shell_commands/tests/test_timeout_config.py +343 -0
  285. autocoder/common/shell_commands/tests/test_timeout_manager.py +520 -0
  286. autocoder/common/shell_commands/timeout_config.py +315 -0
  287. autocoder/common/shell_commands/timeout_manager.py +352 -0
  288. autocoder/common/terminal_paste/__init__.py +14 -0
  289. autocoder/common/terminal_paste/demo.py +145 -0
  290. autocoder/common/terminal_paste/demo_paste_functionality.py +95 -0
  291. autocoder/common/terminal_paste/paste_handler.py +200 -0
  292. autocoder/common/terminal_paste/paste_manager.py +118 -0
  293. autocoder/common/terminal_paste/tests/__init__.py +1 -0
  294. autocoder/common/terminal_paste/tests/test_paste_handler.py +182 -0
  295. autocoder/common/terminal_paste/tests/test_paste_manager.py +126 -0
  296. autocoder/common/terminal_paste/utils.py +163 -0
  297. autocoder/common/test_autocoder_args.py +232 -0
  298. autocoder/common/test_env_manager.py +173 -0
  299. autocoder/common/test_env_manager_integration.py +159 -0
  300. autocoder/common/text_similarity/__init__.py +9 -0
  301. autocoder/common/text_similarity/demo.py +216 -0
  302. autocoder/common/text_similarity/examples.py +266 -0
  303. autocoder/common/text_similarity/test_text_similarity.py +306 -0
  304. autocoder/common/text_similarity/text_similarity.py +194 -0
  305. autocoder/common/text_similarity/utils.py +125 -0
  306. autocoder/common/todos/__init__.py +61 -0
  307. autocoder/common/todos/cache/__init__.py +16 -0
  308. autocoder/common/todos/cache/base_cache.py +89 -0
  309. autocoder/common/todos/cache/cache_manager.py +228 -0
  310. autocoder/common/todos/cache/memory_cache.py +225 -0
  311. autocoder/common/todos/config.py +155 -0
  312. autocoder/common/todos/exceptions.py +35 -0
  313. autocoder/common/todos/get_todo_manager.py +161 -0
  314. autocoder/common/todos/manager.py +537 -0
  315. autocoder/common/todos/models.py +239 -0
  316. autocoder/common/todos/storage/__init__.py +14 -0
  317. autocoder/common/todos/storage/base_storage.py +76 -0
  318. autocoder/common/todos/storage/file_storage.py +278 -0
  319. autocoder/common/tokens/counter.py +24 -2
  320. autocoder/common/tools_manager/__init__.py +17 -0
  321. autocoder/common/tools_manager/examples.py +162 -0
  322. autocoder/common/tools_manager/manager.py +385 -0
  323. autocoder/common/tools_manager/models.py +39 -0
  324. autocoder/common/tools_manager/test_tools_manager.py +303 -0
  325. autocoder/common/tools_manager/utils.py +191 -0
  326. autocoder/common/v2/agent/agentic_callbacks.py +270 -0
  327. autocoder/common/v2/agent/agentic_edit.py +2699 -1856
  328. autocoder/common/v2/agent/agentic_edit_change_manager.py +474 -0
  329. autocoder/common/v2/agent/agentic_edit_tools/__init__.py +35 -1
  330. autocoder/common/v2/agent/agentic_edit_tools/ac_mod_list_tool_resolver.py +279 -0
  331. autocoder/common/v2/agent/agentic_edit_tools/ac_mod_write_tool_resolver.py +10 -1
  332. autocoder/common/v2/agent/agentic_edit_tools/background_task_tool_resolver.py +1167 -0
  333. autocoder/common/v2/agent/agentic_edit_tools/base_tool_resolver.py +2 -2
  334. autocoder/common/v2/agent/agentic_edit_tools/conversation_message_ids_read_tool_resolver.py +214 -0
  335. autocoder/common/v2/agent/agentic_edit_tools/conversation_message_ids_write_tool_resolver.py +299 -0
  336. autocoder/common/v2/agent/agentic_edit_tools/count_tokens_tool_resolver.py +290 -0
  337. autocoder/common/v2/agent/agentic_edit_tools/execute_command_tool_resolver.py +564 -29
  338. autocoder/common/v2/agent/agentic_edit_tools/execute_workflow_tool_resolver.py +485 -0
  339. autocoder/common/v2/agent/agentic_edit_tools/extract_to_text_tool_resolver.py +225 -0
  340. autocoder/common/v2/agent/agentic_edit_tools/lint_report.py +79 -0
  341. autocoder/common/v2/agent/agentic_edit_tools/linter_config_models.py +343 -0
  342. autocoder/common/v2/agent/agentic_edit_tools/linter_enabled_tool_resolver.py +189 -0
  343. autocoder/common/v2/agent/agentic_edit_tools/list_files_tool_resolver.py +169 -101
  344. autocoder/common/v2/agent/agentic_edit_tools/load_extra_document_tool_resolver.py +349 -0
  345. autocoder/common/v2/agent/agentic_edit_tools/read_file_tool_resolver.py +243 -50
  346. autocoder/common/v2/agent/agentic_edit_tools/replace_in_file_tool_resolver.py +667 -147
  347. autocoder/common/v2/agent/agentic_edit_tools/run_named_subagents_tool_resolver.py +691 -0
  348. autocoder/common/v2/agent/agentic_edit_tools/search_files_tool_resolver.py +410 -86
  349. autocoder/common/v2/agent/agentic_edit_tools/session_interactive_tool_resolver.py +115 -0
  350. autocoder/common/v2/agent/agentic_edit_tools/session_start_tool_resolver.py +190 -0
  351. autocoder/common/v2/agent/agentic_edit_tools/session_stop_tool_resolver.py +76 -0
  352. autocoder/common/v2/agent/agentic_edit_tools/test_write_to_file_tool_resolver.py +207 -192
  353. autocoder/common/v2/agent/agentic_edit_tools/todo_read_tool_resolver.py +80 -63
  354. autocoder/common/v2/agent/agentic_edit_tools/todo_write_tool_resolver.py +237 -233
  355. autocoder/common/v2/agent/agentic_edit_tools/use_mcp_tool_resolver.py +2 -2
  356. autocoder/common/v2/agent/agentic_edit_tools/web_crawl_tool_resolver.py +557 -0
  357. autocoder/common/v2/agent/agentic_edit_tools/web_search_tool_resolver.py +600 -0
  358. autocoder/common/v2/agent/agentic_edit_tools/write_to_file_tool_resolver.py +56 -121
  359. autocoder/common/v2/agent/agentic_edit_types.py +343 -9
  360. autocoder/common/v2/agent/runner/__init__.py +3 -3
  361. autocoder/common/v2/agent/runner/base_runner.py +12 -26
  362. autocoder/common/v2/agent/runner/{event_runner.py → file_based_event_runner.py} +3 -2
  363. autocoder/common/v2/agent/runner/sdk_runner.py +150 -8
  364. autocoder/common/v2/agent/runner/terminal_runner.py +170 -57
  365. autocoder/common/v2/agent/runner/tool_display.py +557 -159
  366. autocoder/common/v2/agent/test_agentic_callbacks.py +265 -0
  367. autocoder/common/v2/agent/test_agentic_edit.py +194 -0
  368. autocoder/common/v2/agent/tool_caller/__init__.py +24 -0
  369. autocoder/common/v2/agent/tool_caller/default_tool_resolver_map.py +135 -0
  370. autocoder/common/v2/agent/tool_caller/integration_test.py +172 -0
  371. autocoder/common/v2/agent/tool_caller/plugins/__init__.py +14 -0
  372. autocoder/common/v2/agent/tool_caller/plugins/base_plugin.py +126 -0
  373. autocoder/common/v2/agent/tool_caller/plugins/examples/__init__.py +13 -0
  374. autocoder/common/v2/agent/tool_caller/plugins/examples/logging_plugin.py +164 -0
  375. autocoder/common/v2/agent/tool_caller/plugins/examples/security_filter_plugin.py +198 -0
  376. autocoder/common/v2/agent/tool_caller/plugins/plugin_interface.py +141 -0
  377. autocoder/common/v2/agent/tool_caller/test_tool_caller.py +278 -0
  378. autocoder/common/v2/agent/tool_caller/tool_call_plugin_manager.py +331 -0
  379. autocoder/common/v2/agent/tool_caller/tool_caller.py +337 -0
  380. autocoder/common/v2/agent/tool_caller/usage_example.py +193 -0
  381. autocoder/common/v2/code_agentic_editblock_manager.py +4 -4
  382. autocoder/common/v2/code_auto_generate.py +136 -78
  383. autocoder/common/v2/code_auto_generate_diff.py +135 -79
  384. autocoder/common/v2/code_auto_generate_editblock.py +174 -99
  385. autocoder/common/v2/code_auto_generate_strict_diff.py +151 -71
  386. autocoder/common/v2/code_auto_merge.py +1 -1
  387. autocoder/common/v2/code_auto_merge_editblock.py +13 -1
  388. autocoder/common/v2/code_diff_manager.py +3 -3
  389. autocoder/common/v2/code_editblock_manager.py +4 -14
  390. autocoder/common/v2/code_manager.py +1 -1
  391. autocoder/common/v2/code_strict_diff_manager.py +2 -2
  392. autocoder/common/wrap_llm_hint/__init__.py +10 -0
  393. autocoder/common/wrap_llm_hint/test_wrap_llm_hint.py +1067 -0
  394. autocoder/common/wrap_llm_hint/utils.py +432 -0
  395. autocoder/common/wrap_llm_hint/wrap_llm_hint.py +323 -0
  396. autocoder/completer/__init__.py +8 -0
  397. autocoder/completer/command_completer_v2.py +1051 -0
  398. autocoder/default_project/__init__.py +501 -0
  399. autocoder/dispacher/__init__.py +4 -12
  400. autocoder/dispacher/actions/action.py +165 -7
  401. autocoder/dispacher/actions/plugins/action_regex_project.py +2 -2
  402. autocoder/index/entry.py +116 -124
  403. autocoder/{agent → index/filter}/agentic_filter.py +322 -333
  404. autocoder/index/filter/normal_filter.py +5 -11
  405. autocoder/index/filter/quick_filter.py +1 -1
  406. autocoder/index/index.py +36 -9
  407. autocoder/index/tests/__init__.py +1 -0
  408. autocoder/index/tests/run_tests.py +195 -0
  409. autocoder/index/tests/test_entry.py +303 -0
  410. autocoder/index/tests/test_index_manager.py +314 -0
  411. autocoder/index/tests/test_module_integration.py +300 -0
  412. autocoder/index/tests/test_symbols_utils.py +183 -0
  413. autocoder/inner/__init__.py +4 -0
  414. autocoder/inner/agentic.py +932 -0
  415. autocoder/inner/async_command_handler.py +992 -0
  416. autocoder/inner/conversation_command_handlers.py +623 -0
  417. autocoder/inner/merge_command_handler.py +213 -0
  418. autocoder/inner/queue_command_handler.py +684 -0
  419. autocoder/models.py +95 -266
  420. autocoder/plugins/git_helper_plugin.py +31 -29
  421. autocoder/plugins/token_helper_plugin.py +65 -46
  422. autocoder/pyproject/__init__.py +32 -29
  423. autocoder/rag/agentic_rag.py +215 -75
  424. autocoder/rag/cache/simple_cache.py +1 -2
  425. autocoder/rag/loaders/image_loader.py +1 -1
  426. autocoder/rag/long_context_rag.py +42 -26
  427. autocoder/rag/qa_conversation_strategy.py +1 -1
  428. autocoder/rag/terminal/__init__.py +17 -0
  429. autocoder/rag/terminal/args.py +581 -0
  430. autocoder/rag/terminal/bootstrap.py +61 -0
  431. autocoder/rag/terminal/command_handlers.py +653 -0
  432. autocoder/rag/terminal/formatters/__init__.py +20 -0
  433. autocoder/rag/terminal/formatters/base.py +70 -0
  434. autocoder/rag/terminal/formatters/json_format.py +66 -0
  435. autocoder/rag/terminal/formatters/stream_json.py +95 -0
  436. autocoder/rag/terminal/formatters/text.py +28 -0
  437. autocoder/rag/terminal/init.py +120 -0
  438. autocoder/rag/terminal/utils.py +106 -0
  439. autocoder/rag/test_agentic_rag.py +389 -0
  440. autocoder/rag/test_doc_filter.py +3 -3
  441. autocoder/rag/test_long_context_rag.py +1 -1
  442. autocoder/rag/test_token_limiter.py +517 -10
  443. autocoder/rag/token_counter.py +3 -0
  444. autocoder/rag/token_limiter.py +19 -15
  445. autocoder/rag/tools/__init__.py +26 -2
  446. autocoder/rag/tools/bochaai_example.py +343 -0
  447. autocoder/rag/tools/bochaai_sdk.py +541 -0
  448. autocoder/rag/tools/metaso_example.py +268 -0
  449. autocoder/rag/tools/metaso_sdk.py +417 -0
  450. autocoder/rag/tools/recall_tool.py +28 -7
  451. autocoder/rag/tools/run_integration_tests.py +204 -0
  452. autocoder/rag/tools/test_all_providers.py +318 -0
  453. autocoder/rag/tools/test_bochaai_integration.py +482 -0
  454. autocoder/rag/tools/test_final_integration.py +215 -0
  455. autocoder/rag/tools/test_metaso_integration.py +424 -0
  456. autocoder/rag/tools/test_metaso_real.py +171 -0
  457. autocoder/rag/tools/test_web_crawl_tool.py +639 -0
  458. autocoder/rag/tools/test_web_search_tool.py +509 -0
  459. autocoder/rag/tools/todo_read_tool.py +202 -0
  460. autocoder/rag/tools/todo_write_tool.py +412 -0
  461. autocoder/rag/tools/web_crawl_tool.py +634 -0
  462. autocoder/rag/tools/web_search_tool.py +558 -0
  463. autocoder/rag/tools/web_tools_example.py +119 -0
  464. autocoder/rag/types.py +16 -0
  465. autocoder/rag/variable_holder.py +4 -2
  466. autocoder/rags.py +86 -79
  467. autocoder/regexproject/__init__.py +23 -21
  468. autocoder/sdk/__init__.py +46 -190
  469. autocoder/sdk/api.py +370 -0
  470. autocoder/sdk/async_runner/__init__.py +26 -0
  471. autocoder/sdk/async_runner/async_executor.py +650 -0
  472. autocoder/sdk/async_runner/async_handler.py +356 -0
  473. autocoder/sdk/async_runner/markdown_processor.py +595 -0
  474. autocoder/sdk/async_runner/task_metadata.py +284 -0
  475. autocoder/sdk/async_runner/worktree_manager.py +438 -0
  476. autocoder/sdk/cli/__init__.py +2 -5
  477. autocoder/sdk/cli/formatters.py +28 -204
  478. autocoder/sdk/cli/handlers.py +77 -44
  479. autocoder/sdk/cli/main.py +154 -171
  480. autocoder/sdk/cli/options.py +95 -22
  481. autocoder/sdk/constants.py +139 -51
  482. autocoder/sdk/core/auto_coder_core.py +484 -109
  483. autocoder/sdk/core/bridge.py +297 -115
  484. autocoder/sdk/exceptions.py +18 -12
  485. autocoder/sdk/formatters/__init__.py +19 -0
  486. autocoder/sdk/formatters/input.py +64 -0
  487. autocoder/sdk/formatters/output.py +247 -0
  488. autocoder/sdk/formatters/stream.py +54 -0
  489. autocoder/sdk/models/__init__.py +6 -5
  490. autocoder/sdk/models/options.py +55 -18
  491. autocoder/sdk/utils/formatters.py +27 -195
  492. autocoder/suffixproject/__init__.py +28 -25
  493. autocoder/terminal/__init__.py +14 -0
  494. autocoder/terminal/app.py +454 -0
  495. autocoder/terminal/args.py +32 -0
  496. autocoder/terminal/bootstrap.py +178 -0
  497. autocoder/terminal/command_processor.py +521 -0
  498. autocoder/terminal/command_registry.py +57 -0
  499. autocoder/terminal/help.py +97 -0
  500. autocoder/terminal/tasks/__init__.py +5 -0
  501. autocoder/terminal/tasks/background.py +77 -0
  502. autocoder/terminal/tasks/task_event.py +70 -0
  503. autocoder/terminal/ui/__init__.py +13 -0
  504. autocoder/terminal/ui/completer.py +268 -0
  505. autocoder/terminal/ui/keybindings.py +75 -0
  506. autocoder/terminal/ui/session.py +41 -0
  507. autocoder/terminal/ui/toolbar.py +64 -0
  508. autocoder/terminal/utils/__init__.py +13 -0
  509. autocoder/terminal/utils/errors.py +18 -0
  510. autocoder/terminal/utils/paths.py +19 -0
  511. autocoder/terminal/utils/shell.py +43 -0
  512. autocoder/terminal_v3/__init__.py +10 -0
  513. autocoder/terminal_v3/app.py +201 -0
  514. autocoder/terminal_v3/handlers/__init__.py +5 -0
  515. autocoder/terminal_v3/handlers/command_handler.py +131 -0
  516. autocoder/terminal_v3/models/__init__.py +6 -0
  517. autocoder/terminal_v3/models/conversation_buffer.py +214 -0
  518. autocoder/terminal_v3/models/message.py +50 -0
  519. autocoder/terminal_v3/models/tool_display.py +247 -0
  520. autocoder/terminal_v3/ui/__init__.py +7 -0
  521. autocoder/terminal_v3/ui/keybindings.py +56 -0
  522. autocoder/terminal_v3/ui/layout.py +141 -0
  523. autocoder/terminal_v3/ui/styles.py +43 -0
  524. autocoder/tsproject/__init__.py +23 -23
  525. autocoder/utils/auto_coder_utils/chat_stream_out.py +1 -1
  526. autocoder/utils/llms.py +88 -80
  527. autocoder/utils/math_utils.py +101 -0
  528. autocoder/utils/model_provider_selector.py +16 -4
  529. autocoder/utils/operate_config_api.py +33 -5
  530. autocoder/utils/thread_utils.py +2 -2
  531. autocoder/version.py +4 -2
  532. autocoder/workflow_agents/__init__.py +84 -0
  533. autocoder/workflow_agents/agent.py +143 -0
  534. autocoder/workflow_agents/exceptions.py +573 -0
  535. autocoder/workflow_agents/executor.py +489 -0
  536. autocoder/workflow_agents/loader.py +737 -0
  537. autocoder/workflow_agents/runner.py +267 -0
  538. autocoder/workflow_agents/types.py +172 -0
  539. autocoder/workflow_agents/utils.py +434 -0
  540. autocoder/workflow_agents/workflow_manager.py +211 -0
  541. auto_coder-1.0.0.dist-info/METADATA +0 -396
  542. auto_coder-1.0.0.dist-info/RECORD +0 -442
  543. auto_coder-1.0.0.dist-info/licenses/LICENSE +0 -201
  544. autocoder/auto_coder_server.py +0 -672
  545. autocoder/benchmark.py +0 -138
  546. autocoder/common/ac_style_command_parser/example.py +0 -7
  547. autocoder/common/cleaner.py +0 -31
  548. autocoder/common/command_completer_v2.py +0 -615
  549. autocoder/common/context_pruner.py +0 -477
  550. autocoder/common/conversation_pruner.py +0 -132
  551. autocoder/common/directory_cache/__init__.py +0 -1
  552. autocoder/common/directory_cache/cache.py +0 -192
  553. autocoder/common/directory_cache/test_cache.py +0 -190
  554. autocoder/common/file_checkpoint/examples.py +0 -217
  555. autocoder/common/llm_friendly_package_example.py +0 -138
  556. autocoder/common/llm_friendly_package_test.py +0 -63
  557. autocoder/common/pull_requests/test_module.py +0 -1
  558. autocoder/common/rulefiles/autocoderrules_utils.py +0 -484
  559. autocoder/common/text.py +0 -30
  560. autocoder/common/v2/agent/agentic_edit_tools/list_package_info_tool_resolver.py +0 -42
  561. autocoder/common/v2/agent/agentic_edit_tools/test_execute_command_tool_resolver.py +0 -70
  562. autocoder/common/v2/agent/agentic_edit_tools/test_search_files_tool_resolver.py +0 -163
  563. autocoder/common/v2/agent/agentic_tool_display.py +0 -183
  564. autocoder/plugins/dynamic_completion_example.py +0 -148
  565. autocoder/plugins/sample_plugin.py +0 -160
  566. autocoder/sdk/cli/__main__.py +0 -26
  567. autocoder/sdk/cli/completion_wrapper.py +0 -38
  568. autocoder/sdk/cli/install_completion.py +0 -301
  569. autocoder/sdk/models/messages.py +0 -209
  570. autocoder/sdk/session/__init__.py +0 -32
  571. autocoder/sdk/session/session.py +0 -106
  572. autocoder/sdk/session/session_manager.py +0 -56
  573. {auto_coder-1.0.0.dist-info → auto_coder-2.0.0.dist-info}/top_level.txt +0 -0
  574. /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"])