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
@@ -2,131 +2,455 @@ import os
2
2
  import re
3
3
  import glob
4
4
  from typing import Dict, Any, Optional, List, Union
5
+
6
+ from pydantic import BaseModel, Field
5
7
  from autocoder.common.v2.agent.agentic_edit_tools.base_tool_resolver import BaseToolResolver
6
- # Import ToolResult from types
7
8
  from autocoder.common.v2.agent.agentic_edit_types import SearchFilesTool, ToolResult
8
- from loguru import logger
9
9
  from autocoder.common import AutoCoderArgs
10
+ from autocoder.common.ignorefiles.ignore_file_utils import should_ignore
11
+ from loguru import logger
10
12
  import typing
13
+ import json
11
14
 
12
- from autocoder.common.ignorefiles.ignore_file_utils import should_ignore
15
+ # Import token counter and wrap_llm_hint modules
16
+ from autocoder.common.tokens import count_string_tokens
17
+ from autocoder.common.wrap_llm_hint.utils import add_hint_to_text
13
18
 
14
19
  if typing.TYPE_CHECKING:
15
20
  from autocoder.common.v2.agent.agentic_edit import AgenticEdit
16
21
 
17
22
 
23
+ class SearchParameters(BaseModel):
24
+ """Strongly typed search parameters for file searching operations.
25
+
26
+ This class ensures type safety and validation for all search-related parameters.
27
+ """
28
+ search_path_str: str = Field(..., description="Original search path string for error messages")
29
+ regex_pattern: str = Field(..., description="Regular expression pattern to search for")
30
+ file_pattern: str = Field(..., description="Glob pattern for file filtering (e.g., '*.py')")
31
+ source_dir: str = Field(..., description="Source directory path")
32
+ absolute_source_dir: str = Field(..., description="Absolute path to source directory")
33
+ absolute_search_path: str = Field(..., description="Absolute path to search directory")
34
+
35
+ class Config:
36
+ """Pydantic configuration."""
37
+ frozen = True # Make the class immutable
38
+ extra = "forbid" # Prevent extra fields
39
+
40
+
41
+ class SearchErrorInfo(BaseModel):
42
+ """Information about errors encountered during search operations."""
43
+ file_path: str = Field(..., description="Path to the file/directory that caused the error")
44
+ error_type: str = Field(..., description="Type of error (e.g., 'PermissionError', 'FileNotFoundError')")
45
+ error_message: str = Field(..., description="Detailed error message")
46
+
47
+ class Config:
48
+ """Pydantic configuration."""
49
+ frozen = True
50
+ extra = "forbid"
51
+
52
+
53
+ class SearchMatchInfo(BaseModel):
54
+ """Information about a single search match."""
55
+ path: str = Field(..., description="Relative path to the file containing the match")
56
+ line_number: int = Field(..., description="Line number where the match was found (1-indexed)")
57
+ match_line: str = Field(..., description="The line content that matched the pattern")
58
+ context: str = Field(..., description="Context lines around the match")
59
+
60
+ class Config:
61
+ """Pydantic configuration."""
62
+ frozen = True
63
+ extra = "forbid"
64
+
65
+
66
+ class SearchResultContent(BaseModel):
67
+ """Content structure for search operation results."""
68
+ matches: List[SearchMatchInfo] = Field(..., description="List of search matches found")
69
+ errors: List[SearchErrorInfo] = Field(..., description="List of errors encountered during search")
70
+
71
+ class Config:
72
+ """Pydantic configuration."""
73
+ frozen = True
74
+ extra = "forbid"
75
+
76
+
18
77
  class SearchFilesToolResolver(BaseToolResolver):
78
+ """Resolver for searching files with regex patterns.
79
+
80
+ This class provides functionality to search for text patterns within files
81
+ using regular expressions, with support for file pattern filtering and
82
+ security checks to prevent access outside the project directory.
83
+ """
84
+
85
+ # Constants for search configuration
86
+ MAX_SEARCH_RESULTS = 200
87
+ CONTEXT_LINES_BEFORE = 2
88
+ CONTEXT_LINES_AFTER = 3
89
+ DEFAULT_FILE_PATTERN = "*"
90
+ DEFAULT_SOURCE_DIR = "."
91
+
19
92
  def __init__(self, agent: Optional['AgenticEdit'], tool: SearchFilesTool, args: AutoCoderArgs):
93
+ """Initialize the search files tool resolver.
94
+
95
+ Args:
96
+ agent: Optional AgenticEdit instance
97
+ tool: SearchFilesTool configuration
98
+ args: AutoCoder arguments containing source directory
99
+ """
20
100
  super().__init__(agent, tool, args)
21
101
  self.tool: SearchFilesTool = tool
22
- self.shadow_manager = self.agent.shadow_manager if self.agent else None
23
102
 
24
- def search_in_dir(self, base_dir: str, regex_pattern: str, file_pattern: str, source_dir: str, is_shadow: bool = False, compiled_regex: Optional[re.Pattern] = None) -> List[Dict[str, Any]]:
25
- """Helper function to search in a directory"""
103
+ def search_in_dir(self, base_dir: str, regex_pattern: str, file_pattern: str,
104
+ source_dir: str, is_shadow: bool = False,
105
+ compiled_regex: Optional[re.Pattern] = None) -> tuple[List[SearchMatchInfo], List[SearchErrorInfo]]:
106
+ """Search for regex patterns in files within a directory.
107
+
108
+ Args:
109
+ base_dir: Directory to search in
110
+ regex_pattern: Regular expression pattern to search for
111
+ file_pattern: Glob pattern for file filtering (e.g., '*.py')
112
+ source_dir: Source directory for calculating relative paths
113
+ is_shadow: Whether this is a shadow directory search (legacy parameter)
114
+ compiled_regex: Pre-compiled regex pattern for efficiency
115
+
116
+ Returns:
117
+ Tuple of (search match objects, error information list)
118
+ """
26
119
  search_results = []
120
+ errors = []
27
121
  search_glob_pattern = os.path.join(base_dir, "**", file_pattern)
28
122
 
29
123
  logger.info(
30
- f"Searching for regex '{regex_pattern}' in files matching '{file_pattern}' under '{base_dir}' (shadow: {is_shadow}) with ignore rules applied.")
124
+ f"Searching for regex '{regex_pattern}' in files matching '{file_pattern}' "
125
+ f"under '{base_dir}' (shadow: {is_shadow}) with ignore rules applied."
126
+ )
31
127
 
32
128
  if compiled_regex is None:
33
129
  compiled_regex = re.compile(regex_pattern)
34
130
 
35
- for filepath in glob.glob(search_glob_pattern, recursive=True):
36
- abs_path = os.path.abspath(filepath)
37
- if should_ignore(abs_path):
131
+ try:
132
+ matching_files = glob.glob(search_glob_pattern, recursive=True)
133
+ except (PermissionError, OSError) as e:
134
+ error_info = SearchErrorInfo(
135
+ file_path=base_dir,
136
+ error_type=type(e).__name__,
137
+ error_message=f"Cannot access directory for glob search: {str(e)}"
138
+ )
139
+ errors.append(error_info)
140
+ logger.warning(f"Cannot access directory {base_dir}: {e}")
141
+ return search_results, errors
142
+
143
+ for filepath in matching_files:
144
+ if not self._should_process_file(filepath):
38
145
  continue
146
+
147
+ file_matches, file_errors = self._search_in_file_with_errors(filepath, compiled_regex, source_dir)
148
+ search_results.extend(file_matches)
149
+ errors.extend(file_errors)
39
150
 
40
- if os.path.isfile(filepath):
41
- try:
42
- with open(filepath, 'r', encoding='utf-8', errors='replace') as f:
43
- lines = f.readlines()
44
- for i, line in enumerate(lines):
45
- if compiled_regex.search(line):
46
- context_start = max(0, i - 2)
47
- context_end = min(len(lines), i + 3)
48
- context = "".join(
49
- [f"{j+1}: {lines[j]}" for j in range(context_start, context_end)])
50
-
51
- if is_shadow and self.shadow_manager:
52
- try:
53
- abs_project_path = self.shadow_manager.from_shadow_path(
54
- filepath)
55
- relative_path = os.path.relpath(
56
- abs_project_path, source_dir)
57
- except Exception:
58
- relative_path = os.path.relpath(
59
- filepath, source_dir)
60
- else:
61
- relative_path = os.path.relpath(
62
- filepath, source_dir)
63
-
64
- search_results.append({
65
- "path": relative_path,
66
- "line_number": i + 1,
67
- "match_line": line.strip(),
68
- "context": context.strip()
69
- })
70
- except Exception as e:
71
- logger.warning(
72
- f"Could not read or process file {filepath}: {e}")
73
- continue
74
-
75
- return search_results
76
-
77
- def search_files_normal(self, search_path_str: str, regex_pattern: str, file_pattern: str, source_dir: str, absolute_source_dir: str, absolute_search_path: str) -> Union[ToolResult, List[Dict[str, Any]]]:
78
- """Search files directly without using shadow manager"""
79
- # Security check
80
- if not absolute_search_path.startswith(absolute_source_dir):
81
- return ToolResult(success=False, message=f"Error: Access denied. Attempted to search outside the project directory: {search_path_str}")
151
+ return search_results, errors
152
+
153
+ def _should_process_file(self, filepath: str) -> bool:
154
+ """Check if a file should be processed for searching.
155
+
156
+ Args:
157
+ filepath: Path to the file to check
158
+
159
+ Returns:
160
+ True if the file should be processed, False otherwise
161
+ """
162
+ abs_path = os.path.abspath(filepath)
163
+ return os.path.isfile(filepath) and not should_ignore(abs_path)
164
+
165
+ def _search_in_file(self, filepath: str, compiled_regex: re.Pattern,
166
+ source_dir: str) -> List[SearchMatchInfo]:
167
+ """Search for regex matches within a single file.
168
+
169
+ Args:
170
+ filepath: Path to the file to search
171
+ compiled_regex: Compiled regular expression pattern
172
+ source_dir: Source directory for calculating relative paths
173
+
174
+ Returns:
175
+ List of SearchMatchInfo objects for this file
176
+ """
177
+ file_matches, _ = self._search_in_file_with_errors(filepath, compiled_regex, source_dir)
178
+ return file_matches
179
+
180
+ def _search_in_file_with_errors(self, filepath: str, compiled_regex: re.Pattern,
181
+ source_dir: str) -> tuple[List[SearchMatchInfo], List[SearchErrorInfo]]:
182
+ """Search for regex matches within a single file, collecting errors.
183
+
184
+ Args:
185
+ filepath: Path to the file to search
186
+ compiled_regex: Compiled regular expression pattern
187
+ source_dir: Source directory for calculating relative paths
188
+
189
+ Returns:
190
+ Tuple of (SearchMatchInfo objects, error information list)
191
+ """
192
+ file_matches = []
193
+ errors = []
194
+
195
+ try:
196
+ with open(filepath, 'r', encoding='utf-8', errors='replace') as f:
197
+ lines = f.readlines()
198
+
199
+ for line_index, line in enumerate(lines):
200
+ if compiled_regex.search(line):
201
+ match_info = self._create_match_info(
202
+ filepath, line_index, line, lines, source_dir
203
+ )
204
+ file_matches.append(match_info)
205
+
206
+ except (PermissionError, OSError, UnicodeDecodeError) as e:
207
+ error_info = SearchErrorInfo(
208
+ file_path=filepath,
209
+ error_type=type(e).__name__,
210
+ error_message=f"Cannot read file: {str(e)}"
211
+ )
212
+ errors.append(error_info)
213
+ logger.warning(f"Could not read or process file {filepath}: {e}")
214
+ except Exception as e:
215
+ error_info = SearchErrorInfo(
216
+ file_path=filepath,
217
+ error_type=type(e).__name__,
218
+ error_message=f"Unexpected error: {str(e)}"
219
+ )
220
+ errors.append(error_info)
221
+ logger.warning(f"Unexpected error processing file {filepath}: {e}")
222
+
223
+ return file_matches, errors
224
+
225
+ def _create_match_info(self, filepath: str, line_index: int, line: str,
226
+ all_lines: List[str], source_dir: str) -> SearchMatchInfo:
227
+ """Create a match information object.
228
+
229
+ Args:
230
+ filepath: Path to the file containing the match
231
+ line_index: Zero-based index of the matching line
232
+ line: The matching line content
233
+ all_lines: All lines in the file for context
234
+ source_dir: Source directory for calculating relative paths
235
+
236
+ Returns:
237
+ SearchMatchInfo object containing match information
238
+ """
239
+ context_start = max(0, line_index - self.CONTEXT_LINES_BEFORE)
240
+ context_end = min(len(all_lines), line_index + self.CONTEXT_LINES_AFTER)
241
+
242
+ context_lines = [
243
+ f"{j + 1}: {all_lines[j]}"
244
+ for j in range(context_start, context_end)
245
+ ]
246
+ context = "".join(context_lines)
247
+
248
+ relative_path = os.path.relpath(filepath, source_dir)
249
+
250
+ return SearchMatchInfo(
251
+ path=relative_path,
252
+ line_number=line_index + 1,
253
+ match_line=line.strip(),
254
+ context=context.strip()
255
+ )
82
256
 
83
- # Validate that the directory exists
84
- if not os.path.exists(absolute_search_path):
85
- return ToolResult(success=False, message=f"Error: Search path not found: {search_path_str}")
86
- if not os.path.isdir(absolute_search_path):
87
- return ToolResult(success=False, message=f"Error: Search path is not a directory: {search_path_str}")
257
+ def search_files_normal(self, search_path_str: str, regex_pattern: str,
258
+ file_pattern: str, source_dir: str,
259
+ absolute_source_dir: str, absolute_search_path: str) -> Union[ToolResult, tuple[List[SearchMatchInfo], List[SearchErrorInfo]]]:
260
+ """Search files directly in the specified directory or file.
261
+
262
+ Args:
263
+ search_path_str: Original search path string (for error messages)
264
+ regex_pattern: Regular expression pattern to search for
265
+ file_pattern: Glob pattern for file filtering
266
+ source_dir: Source directory path
267
+ absolute_source_dir: Absolute path to source directory
268
+ absolute_search_path: Absolute path to search directory or file
269
+
270
+ Returns:
271
+ ToolResult on error, or tuple of (SearchMatchInfo objects, error information) on success
272
+ """
273
+ # Perform security and validation checks
274
+ validation_result = self._validate_search_path(
275
+ search_path_str, absolute_source_dir, absolute_search_path
276
+ )
277
+ if validation_result:
278
+ return validation_result
88
279
 
89
280
  try:
90
281
  compiled_regex = re.compile(regex_pattern)
91
-
92
- # Search in the directory
93
- search_results = self.search_in_dir(
94
- absolute_search_path, regex_pattern, file_pattern, source_dir, is_shadow=False, compiled_regex=compiled_regex)
95
-
96
- return search_results
282
+
283
+ # Check if the path is a file or directory
284
+ if os.path.isfile(absolute_search_path):
285
+ # Search in single file
286
+ logger.info(f"Searching for regex '{regex_pattern}' in file '{absolute_search_path}'")
287
+ if not self._should_process_file(absolute_search_path):
288
+ return [], []
289
+ search_results, errors = self._search_in_file_with_errors(absolute_search_path, compiled_regex, source_dir)
290
+ else:
291
+ # Search in directory
292
+ search_results, errors = self.search_in_dir(
293
+ absolute_search_path, regex_pattern, file_pattern,
294
+ source_dir, is_shadow=False, compiled_regex=compiled_regex
295
+ )
296
+
297
+ return search_results, errors
97
298
 
98
299
  except re.error as e:
300
+ error_msg = f"Invalid regex pattern: {e}"
99
301
  logger.error(f"Invalid regex pattern '{regex_pattern}': {e}")
100
- return ToolResult(success=False, message=f"Invalid regex pattern: {e}")
302
+ return ToolResult(success=False, message=error_msg)
303
+
101
304
  except Exception as e:
305
+ error_msg = f"An unexpected error occurred during search: {str(e)}"
102
306
  logger.error(f"Error during file search: {str(e)}")
103
- return ToolResult(success=False, message=f"An unexpected error occurred during search: {str(e)}")
307
+ return ToolResult(success=False, message=error_msg)
308
+
309
+ def _validate_search_path(self, search_path_str: str, absolute_source_dir: str,
310
+ absolute_search_path: str) -> Optional[ToolResult]:
311
+ """Validate the search path for security and existence.
312
+
313
+ Args:
314
+ search_path_str: Original search path string (for error messages)
315
+ absolute_source_dir: Absolute path to source directory
316
+ absolute_search_path: Absolute path to search directory or file
317
+
318
+ Returns:
319
+ ToolResult with error if validation fails, None if validation passes
320
+ """
321
+ # Security check: prevent access outside project directory
322
+ if not absolute_search_path.startswith(absolute_source_dir):
323
+ return ToolResult(
324
+ success=False,
325
+ message=f"Error: Access denied. Attempted to search outside the project directory: {search_path_str}"
326
+ )
327
+
328
+ # Check if path exists
329
+ if not os.path.exists(absolute_search_path):
330
+ return ToolResult(
331
+ success=False,
332
+ message=f"Error: Search path not found: {search_path_str}"
333
+ )
334
+
335
+ return None
104
336
 
105
337
  def resolve(self) -> ToolResult:
106
- """Resolve the search files tool by calling the appropriate implementation"""
338
+ """Resolve the search files tool by executing the search operation.
339
+
340
+ Returns:
341
+ ToolResult containing search results or error information
342
+ """
343
+ search_params = self._extract_search_parameters()
344
+
345
+ result = self.search_files_normal(
346
+ search_params.search_path_str,
347
+ search_params.regex_pattern,
348
+ search_params.file_pattern,
349
+ search_params.source_dir,
350
+ search_params.absolute_source_dir,
351
+ search_params.absolute_search_path
352
+ )
353
+
354
+ return self._format_search_result(result)
355
+
356
+ def _extract_search_parameters(self) -> SearchParameters:
357
+ """Extract and prepare search parameters from tool configuration.
358
+
359
+ Returns:
360
+ SearchParameters instance with strongly typed parameters
361
+ """
107
362
  search_path_str = self.tool.path
108
363
  regex_pattern = self.tool.regex
109
- file_pattern = self.tool.file_pattern or "*"
110
- source_dir = self.args.source_dir or "."
364
+ file_pattern = self.tool.file_pattern or self.DEFAULT_FILE_PATTERN
365
+ source_dir = self.args.source_dir or self.DEFAULT_SOURCE_DIR
111
366
  absolute_source_dir = os.path.abspath(source_dir)
112
367
  absolute_search_path = os.path.abspath(
113
- os.path.join(source_dir, search_path_str))
114
-
115
- result = self.search_files_normal(
116
- search_path_str, regex_pattern, file_pattern, source_dir, absolute_source_dir, absolute_search_path)
117
-
118
- # Handle the case where the implementation returns a list instead of a ToolResult
119
- if isinstance(result, list):
120
- total_results = len(result)
121
- # Limit results to 200 if needed
122
- if total_results > 200:
123
- truncated_results = result[:200]
124
- message = f"Search completed. Found {total_results} matches, showing only the first 200."
125
- logger.info(message)
126
- return ToolResult(success=True, message=message, content=truncated_results)
368
+ os.path.join(source_dir, search_path_str)
369
+ )
370
+
371
+ return SearchParameters(
372
+ search_path_str=search_path_str,
373
+ regex_pattern=regex_pattern,
374
+ file_pattern=file_pattern,
375
+ source_dir=source_dir,
376
+ absolute_source_dir=absolute_source_dir,
377
+ absolute_search_path=absolute_search_path
378
+ )
379
+
380
+ def _format_search_result(self, result: Union[ToolResult, tuple[List[SearchMatchInfo], List[SearchErrorInfo]]]) -> ToolResult:
381
+ """Format the search result into a standardized ToolResult.
382
+
383
+ Args:
384
+ result: Raw search result (either ToolResult or tuple of SearchMatchInfo objects and errors)
385
+
386
+ Returns:
387
+ Formatted ToolResult
388
+ """
389
+ # If result is already a ToolResult (error case), return it directly
390
+ if isinstance(result, ToolResult):
391
+ return result
392
+
393
+ # Handle successful search results (tuple of matches and errors)
394
+ search_results, errors = result
395
+ total_results = len(search_results)
396
+ total_errors = len(errors)
397
+
398
+ # Prepare error summary for message
399
+ error_summary = ""
400
+ if total_errors > 0:
401
+ error_types = {}
402
+ for error in errors:
403
+ error_types[error.error_type] = error_types.get(error.error_type, 0) + 1
404
+ error_summary = f" Encountered {total_errors} errors: " + ", ".join([f"{count} {error_type}" for error_type, count in error_types.items()])
405
+
406
+ # Prepare content with both results and errors using Pydantic model
407
+ truncated_matches = search_results[:self.MAX_SEARCH_RESULTS] if total_results > self.MAX_SEARCH_RESULTS else search_results
408
+ content_model = SearchResultContent(
409
+ matches=truncated_matches,
410
+ errors=errors
411
+ )
412
+ content = content_model.model_dump()
413
+
414
+ # Convert content to JSON string to count tokens
415
+ content_str = json.dumps(content, ensure_ascii=False, indent=2)
416
+ token_count = count_string_tokens(content_str)
417
+
418
+ # Check if content exceeds 5k tokens
419
+ MAX_TOKENS = 5000
420
+ if token_count > MAX_TOKENS:
421
+ # Truncate to first 1000 characters
422
+ truncated_content_str = content_str[:1000]
423
+
424
+ # Add hint about truncation
425
+ hint_message = "Search results truncated due to exceeding 5k tokens. Try narrowing your search by using more specific regex patterns or file patterns to reduce output."
426
+ truncated_content_str = add_hint_to_text(truncated_content_str, hint_message)
427
+
428
+ # Log the truncation
429
+ logger.warning(f"Search results truncated from {token_count} tokens to first 1000 characters")
430
+
431
+ # Create truncation message
432
+ if total_results > self.MAX_SEARCH_RESULTS:
433
+ message = (
434
+ f"Search completed. Found {total_results} matches (showing first {self.MAX_SEARCH_RESULTS}), "
435
+ f"but results were truncated due to size (original: {token_count} tokens).{error_summary}"
436
+ )
127
437
  else:
128
- message = f"Search completed. Found {total_results} matches."
129
- logger.info(message)
130
- return ToolResult(success=True, message=message, content=result)
438
+ message = (
439
+ f"Search completed. Found {total_results} matches, "
440
+ f"but results were truncated due to size (original: {token_count} tokens).{error_summary}"
441
+ )
442
+
443
+ return ToolResult(success=True, message=message, content=truncated_content_str)
444
+
445
+ # Normal case - content within token limit
446
+ if total_results > self.MAX_SEARCH_RESULTS:
447
+ message = (
448
+ f"Search completed. Found {total_results} matches, "
449
+ f"showing only the first {self.MAX_SEARCH_RESULTS}.{error_summary}"
450
+ )
451
+ logger.info(message)
452
+ return ToolResult(success=True, message=message, content=content)
131
453
  else:
132
- return result
454
+ message = f"Search completed. Found {total_results} matches.{error_summary}"
455
+ logger.info(message)
456
+ return ToolResult(success=True, message=message, content=content)
@@ -0,0 +1,115 @@
1
+ """
2
+ Session interactive tool resolver for interacting with active sessions.
3
+ """
4
+
5
+ from typing import Optional
6
+ from loguru import logger
7
+
8
+ from autocoder.common.v2.agent.agentic_edit_tools.base_tool_resolver import BaseToolResolver
9
+ from autocoder.common.v2.agent.agentic_edit_types import SessionInteractiveTool, ToolResult
10
+ from autocoder.common.shell_commands import get_session_manager
11
+ from autocoder.common import AutoCoderArgs
12
+
13
+ import typing
14
+ if typing.TYPE_CHECKING:
15
+ from autocoder.common.v2.agent.agentic_edit import AgenticEdit
16
+
17
+
18
+ class SessionInteractiveToolResolver(BaseToolResolver):
19
+ """Resolver for interacting with active command sessions."""
20
+
21
+ def __init__(self, agent: Optional['AgenticEdit'], tool: SessionInteractiveTool, args: AutoCoderArgs):
22
+ super().__init__(agent, tool, args)
23
+ self.tool: SessionInteractiveTool = tool
24
+ self.session_manager = get_session_manager()
25
+
26
+ def resolve(self) -> ToolResult:
27
+ """
28
+ Send input to a session and read output.
29
+
30
+ Returns:
31
+ ToolResult with session output
32
+ """
33
+ session_id = self.tool.session_id
34
+ input_text = self.tool.input
35
+ read_timeout = self.tool.read_timeout
36
+ max_bytes = self.tool.max_bytes
37
+ expect_prompt = self.tool.expect_prompt
38
+ prompt_regex = self.tool.prompt_regex
39
+
40
+ logger.debug(
41
+ f"Sending input to session {session_id}: {input_text[:50]}...")
42
+
43
+ # Send input to session
44
+ result = self.session_manager.send_input(
45
+ session_id=session_id,
46
+ input_text=input_text,
47
+ read_timeout=read_timeout,
48
+ max_bytes=max_bytes,
49
+ expect_prompt=expect_prompt,
50
+ prompt_regex=prompt_regex
51
+ )
52
+
53
+ if result.success:
54
+ # Handle both dict and string content
55
+ output = ''
56
+ raw_output = ''
57
+ cleaned_length = 0
58
+
59
+ if isinstance(result.content, dict):
60
+ output = result.content.get('output', '')
61
+ raw_output = result.content.get('raw_output', '')
62
+ cleaned_length = result.content.get('cleaned_length', 0)
63
+ elif isinstance(result.content, str):
64
+ output = result.content
65
+ raw_output = result.content
66
+ cleaned_length = len(result.content)
67
+
68
+ logger.debug(
69
+ f"Session {session_id} output: {len(output)} characters")
70
+
71
+ # Format content as readable text
72
+ if output.strip():
73
+ lines = output.strip().split('\n')
74
+ line_count = len(lines)
75
+
76
+ # Create formatted text output
77
+ formatted_content = f"""Session ID: {session_id}
78
+ Input: {input_text}
79
+ Output ({line_count} lines):
80
+ {'-' * 50}
81
+ {output}
82
+ {'-' * 50}
83
+ Status: Success - Received {line_count} lines of output"""
84
+
85
+ return ToolResult(
86
+ success=True,
87
+ message=f"Input sent successfully. Received {line_count} lines of output",
88
+ content=formatted_content
89
+ )
90
+ else:
91
+ # No output case
92
+ formatted_content = f"""Session ID: {session_id}
93
+ Input: {input_text}
94
+ Output: (no output)
95
+ Status: Success - No output received"""
96
+
97
+ return ToolResult(
98
+ success=True,
99
+ message="Input sent successfully. No output received.",
100
+ content=formatted_content
101
+ )
102
+ else:
103
+ # Error case - format as text as well
104
+ formatted_content = f"""Session ID: {session_id}
105
+ Input: {input_text}
106
+ Status: Error - {result.message}"""
107
+
108
+ logger.error(
109
+ f"Failed to interact with session {session_id}: {result.message}")
110
+
111
+ return ToolResult(
112
+ success=False,
113
+ message=result.message,
114
+ content=formatted_content
115
+ )