autobyteus 1.2.1__py3-none-any.whl → 1.3.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.
Files changed (472) hide show
  1. autobyteus/agent/agent.py +15 -5
  2. autobyteus/agent/bootstrap_steps/__init__.py +3 -3
  3. autobyteus/agent/bootstrap_steps/agent_bootstrapper.py +5 -59
  4. autobyteus/agent/bootstrap_steps/base_bootstrap_step.py +1 -4
  5. autobyteus/agent/bootstrap_steps/mcp_server_prewarming_step.py +1 -3
  6. autobyteus/agent/bootstrap_steps/system_prompt_processing_step.py +16 -13
  7. autobyteus/agent/bootstrap_steps/working_context_snapshot_restore_step.py +38 -0
  8. autobyteus/agent/bootstrap_steps/workspace_context_initialization_step.py +2 -4
  9. autobyteus/agent/context/agent_config.py +47 -20
  10. autobyteus/agent/context/agent_context.py +23 -18
  11. autobyteus/agent/context/agent_runtime_state.py +21 -19
  12. autobyteus/agent/events/__init__.py +16 -1
  13. autobyteus/agent/events/agent_events.py +43 -3
  14. autobyteus/agent/events/agent_input_event_queue_manager.py +79 -26
  15. autobyteus/agent/events/event_store.py +57 -0
  16. autobyteus/agent/events/notifiers.py +69 -59
  17. autobyteus/agent/events/worker_event_dispatcher.py +21 -64
  18. autobyteus/agent/factory/agent_factory.py +83 -6
  19. autobyteus/agent/handlers/__init__.py +2 -0
  20. autobyteus/agent/handlers/approved_tool_invocation_event_handler.py +51 -34
  21. autobyteus/agent/handlers/bootstrap_event_handler.py +155 -0
  22. autobyteus/agent/handlers/inter_agent_message_event_handler.py +10 -0
  23. autobyteus/agent/handlers/lifecycle_event_logger.py +19 -11
  24. autobyteus/agent/handlers/llm_complete_response_received_event_handler.py +10 -15
  25. autobyteus/agent/handlers/llm_user_message_ready_event_handler.py +188 -48
  26. autobyteus/agent/handlers/tool_execution_approval_event_handler.py +0 -10
  27. autobyteus/agent/handlers/tool_invocation_request_event_handler.py +53 -48
  28. autobyteus/agent/handlers/tool_result_event_handler.py +7 -8
  29. autobyteus/agent/handlers/user_input_message_event_handler.py +10 -3
  30. autobyteus/agent/input_processor/memory_ingest_input_processor.py +44 -0
  31. autobyteus/agent/lifecycle/__init__.py +12 -0
  32. autobyteus/agent/lifecycle/base_processor.py +109 -0
  33. autobyteus/agent/lifecycle/events.py +35 -0
  34. autobyteus/agent/lifecycle/processor_definition.py +36 -0
  35. autobyteus/agent/lifecycle/processor_registry.py +106 -0
  36. autobyteus/agent/llm_request_assembler.py +98 -0
  37. autobyteus/agent/llm_response_processor/__init__.py +1 -8
  38. autobyteus/agent/message/context_file_type.py +1 -1
  39. autobyteus/agent/runtime/agent_runtime.py +29 -21
  40. autobyteus/agent/runtime/agent_worker.py +98 -19
  41. autobyteus/agent/shutdown_steps/__init__.py +2 -0
  42. autobyteus/agent/shutdown_steps/agent_shutdown_orchestrator.py +2 -0
  43. autobyteus/agent/shutdown_steps/tool_cleanup_step.py +58 -0
  44. autobyteus/agent/status/__init__.py +14 -0
  45. autobyteus/agent/status/manager.py +93 -0
  46. autobyteus/agent/status/status_deriver.py +96 -0
  47. autobyteus/agent/{phases/phase_enum.py → status/status_enum.py} +16 -16
  48. autobyteus/agent/status/status_update_utils.py +73 -0
  49. autobyteus/agent/streaming/__init__.py +52 -5
  50. autobyteus/agent/streaming/adapters/__init__.py +18 -0
  51. autobyteus/agent/streaming/adapters/invocation_adapter.py +184 -0
  52. autobyteus/agent/streaming/adapters/tool_call_parsing.py +163 -0
  53. autobyteus/agent/streaming/adapters/tool_syntax_registry.py +67 -0
  54. autobyteus/agent/streaming/agent_event_stream.py +3 -183
  55. autobyteus/agent/streaming/api_tool_call/__init__.py +16 -0
  56. autobyteus/agent/streaming/api_tool_call/file_content_streamer.py +56 -0
  57. autobyteus/agent/streaming/api_tool_call/json_string_field_extractor.py +175 -0
  58. autobyteus/agent/streaming/api_tool_call_streaming_response_handler.py +4 -0
  59. autobyteus/agent/streaming/events/__init__.py +6 -0
  60. autobyteus/agent/streaming/events/stream_event_payloads.py +284 -0
  61. autobyteus/agent/streaming/events/stream_events.py +141 -0
  62. autobyteus/agent/streaming/handlers/__init__.py +15 -0
  63. autobyteus/agent/streaming/handlers/api_tool_call_streaming_response_handler.py +303 -0
  64. autobyteus/agent/streaming/handlers/parsing_streaming_response_handler.py +107 -0
  65. autobyteus/agent/streaming/handlers/pass_through_streaming_response_handler.py +107 -0
  66. autobyteus/agent/streaming/handlers/streaming_handler_factory.py +177 -0
  67. autobyteus/agent/streaming/handlers/streaming_response_handler.py +58 -0
  68. autobyteus/agent/streaming/parser/__init__.py +61 -0
  69. autobyteus/agent/streaming/parser/event_emitter.py +181 -0
  70. autobyteus/agent/streaming/parser/events.py +4 -0
  71. autobyteus/agent/streaming/parser/invocation_adapter.py +4 -0
  72. autobyteus/agent/streaming/parser/json_parsing_strategies/__init__.py +19 -0
  73. autobyteus/agent/streaming/parser/json_parsing_strategies/base.py +32 -0
  74. autobyteus/agent/streaming/parser/json_parsing_strategies/default.py +34 -0
  75. autobyteus/agent/streaming/parser/json_parsing_strategies/gemini.py +31 -0
  76. autobyteus/agent/streaming/parser/json_parsing_strategies/openai.py +64 -0
  77. autobyteus/agent/streaming/parser/json_parsing_strategies/registry.py +75 -0
  78. autobyteus/agent/streaming/parser/parser_context.py +227 -0
  79. autobyteus/agent/streaming/parser/parser_factory.py +132 -0
  80. autobyteus/agent/streaming/parser/sentinel_format.py +7 -0
  81. autobyteus/agent/streaming/parser/state_factory.py +62 -0
  82. autobyteus/agent/streaming/parser/states/__init__.py +1 -0
  83. autobyteus/agent/streaming/parser/states/base_state.py +60 -0
  84. autobyteus/agent/streaming/parser/states/custom_xml_tag_run_bash_parsing_state.py +38 -0
  85. autobyteus/agent/streaming/parser/states/custom_xml_tag_write_file_parsing_state.py +55 -0
  86. autobyteus/agent/streaming/parser/states/delimited_content_state.py +146 -0
  87. autobyteus/agent/streaming/parser/states/json_initialization_state.py +144 -0
  88. autobyteus/agent/streaming/parser/states/json_tool_parsing_state.py +137 -0
  89. autobyteus/agent/streaming/parser/states/sentinel_content_state.py +30 -0
  90. autobyteus/agent/streaming/parser/states/sentinel_initialization_state.py +117 -0
  91. autobyteus/agent/streaming/parser/states/text_state.py +78 -0
  92. autobyteus/agent/streaming/parser/states/xml_patch_file_tool_parsing_state.py +328 -0
  93. autobyteus/agent/streaming/parser/states/xml_run_bash_tool_parsing_state.py +129 -0
  94. autobyteus/agent/streaming/parser/states/xml_tag_initialization_state.py +151 -0
  95. autobyteus/agent/streaming/parser/states/xml_tool_parsing_state.py +63 -0
  96. autobyteus/agent/streaming/parser/states/xml_write_file_tool_parsing_state.py +343 -0
  97. autobyteus/agent/streaming/parser/strategies/__init__.py +17 -0
  98. autobyteus/agent/streaming/parser/strategies/base.py +24 -0
  99. autobyteus/agent/streaming/parser/strategies/json_tool_strategy.py +26 -0
  100. autobyteus/agent/streaming/parser/strategies/registry.py +28 -0
  101. autobyteus/agent/streaming/parser/strategies/sentinel_strategy.py +23 -0
  102. autobyteus/agent/streaming/parser/strategies/xml_tag_strategy.py +21 -0
  103. autobyteus/agent/streaming/parser/stream_scanner.py +167 -0
  104. autobyteus/agent/streaming/parser/streaming_parser.py +212 -0
  105. autobyteus/agent/streaming/parser/tool_call_parsing.py +4 -0
  106. autobyteus/agent/streaming/parser/tool_constants.py +7 -0
  107. autobyteus/agent/streaming/parser/tool_syntax_registry.py +4 -0
  108. autobyteus/agent/streaming/parser/xml_tool_parsing_state_registry.py +55 -0
  109. autobyteus/agent/streaming/parsing_streaming_response_handler.py +4 -0
  110. autobyteus/agent/streaming/pass_through_streaming_response_handler.py +4 -0
  111. autobyteus/agent/streaming/queue_streamer.py +3 -57
  112. autobyteus/agent/streaming/segments/__init__.py +5 -0
  113. autobyteus/agent/streaming/segments/segment_events.py +82 -0
  114. autobyteus/agent/streaming/stream_event_payloads.py +2 -223
  115. autobyteus/agent/streaming/stream_events.py +3 -140
  116. autobyteus/agent/streaming/streaming_handler_factory.py +4 -0
  117. autobyteus/agent/streaming/streaming_response_handler.py +4 -0
  118. autobyteus/agent/streaming/streams/__init__.py +5 -0
  119. autobyteus/agent/streaming/streams/agent_event_stream.py +197 -0
  120. autobyteus/agent/streaming/utils/__init__.py +5 -0
  121. autobyteus/agent/streaming/utils/queue_streamer.py +59 -0
  122. autobyteus/agent/system_prompt_processor/__init__.py +2 -0
  123. autobyteus/agent/system_prompt_processor/available_skills_processor.py +96 -0
  124. autobyteus/agent/system_prompt_processor/base_processor.py +1 -1
  125. autobyteus/agent/system_prompt_processor/processor_meta.py +15 -2
  126. autobyteus/agent/system_prompt_processor/tool_manifest_injector_processor.py +39 -58
  127. autobyteus/agent/token_budget.py +56 -0
  128. autobyteus/agent/tool_execution_result_processor/memory_ingest_tool_result_processor.py +29 -0
  129. autobyteus/agent/tool_invocation.py +16 -40
  130. autobyteus/agent/tool_invocation_preprocessor/__init__.py +9 -0
  131. autobyteus/agent/tool_invocation_preprocessor/base_preprocessor.py +45 -0
  132. autobyteus/agent/tool_invocation_preprocessor/processor_definition.py +15 -0
  133. autobyteus/agent/tool_invocation_preprocessor/processor_meta.py +33 -0
  134. autobyteus/agent/tool_invocation_preprocessor/processor_registry.py +60 -0
  135. autobyteus/agent/utils/wait_for_idle.py +12 -14
  136. autobyteus/agent/workspace/base_workspace.py +6 -27
  137. autobyteus/agent_team/agent_team.py +3 -3
  138. autobyteus/agent_team/agent_team_builder.py +1 -41
  139. autobyteus/agent_team/bootstrap_steps/__init__.py +0 -4
  140. autobyteus/agent_team/bootstrap_steps/agent_configuration_preparation_step.py +8 -18
  141. autobyteus/agent_team/bootstrap_steps/agent_team_bootstrapper.py +4 -16
  142. autobyteus/agent_team/bootstrap_steps/base_agent_team_bootstrap_step.py +1 -2
  143. autobyteus/agent_team/bootstrap_steps/coordinator_initialization_step.py +1 -2
  144. autobyteus/agent_team/bootstrap_steps/task_notifier_initialization_step.py +1 -2
  145. autobyteus/agent_team/bootstrap_steps/team_context_initialization_step.py +4 -4
  146. autobyteus/agent_team/context/agent_team_config.py +6 -3
  147. autobyteus/agent_team/context/agent_team_context.py +25 -3
  148. autobyteus/agent_team/context/agent_team_runtime_state.py +9 -6
  149. autobyteus/agent_team/events/__init__.py +11 -0
  150. autobyteus/agent_team/events/agent_team_event_dispatcher.py +22 -9
  151. autobyteus/agent_team/events/agent_team_events.py +16 -0
  152. autobyteus/agent_team/events/event_store.py +57 -0
  153. autobyteus/agent_team/factory/agent_team_factory.py +8 -0
  154. autobyteus/agent_team/handlers/inter_agent_message_request_event_handler.py +18 -2
  155. autobyteus/agent_team/handlers/lifecycle_agent_team_event_handler.py +21 -5
  156. autobyteus/agent_team/handlers/process_user_message_event_handler.py +17 -8
  157. autobyteus/agent_team/handlers/tool_approval_team_event_handler.py +19 -4
  158. autobyteus/agent_team/runtime/agent_team_runtime.py +41 -10
  159. autobyteus/agent_team/runtime/agent_team_worker.py +69 -5
  160. autobyteus/agent_team/status/__init__.py +14 -0
  161. autobyteus/agent_team/status/agent_team_status.py +18 -0
  162. autobyteus/agent_team/status/agent_team_status_manager.py +33 -0
  163. autobyteus/agent_team/status/status_deriver.py +62 -0
  164. autobyteus/agent_team/status/status_update_utils.py +42 -0
  165. autobyteus/agent_team/streaming/__init__.py +2 -2
  166. autobyteus/agent_team/streaming/agent_team_event_notifier.py +6 -6
  167. autobyteus/agent_team/streaming/agent_team_stream_event_payloads.py +4 -4
  168. autobyteus/agent_team/streaming/agent_team_stream_events.py +3 -3
  169. autobyteus/agent_team/system_prompt_processor/__init__.py +6 -0
  170. autobyteus/agent_team/system_prompt_processor/team_manifest_injector_processor.py +76 -0
  171. autobyteus/agent_team/task_notification/task_notification_mode.py +19 -0
  172. autobyteus/agent_team/utils/wait_for_idle.py +4 -4
  173. autobyteus/cli/agent_cli.py +18 -10
  174. autobyteus/cli/agent_team_tui/app.py +14 -11
  175. autobyteus/cli/agent_team_tui/state.py +13 -15
  176. autobyteus/cli/agent_team_tui/widgets/agent_list_sidebar.py +15 -15
  177. autobyteus/cli/agent_team_tui/widgets/focus_pane.py +143 -36
  178. autobyteus/cli/agent_team_tui/widgets/renderables.py +1 -1
  179. autobyteus/cli/agent_team_tui/widgets/shared.py +25 -25
  180. autobyteus/cli/cli_display.py +193 -44
  181. autobyteus/cli/workflow_tui/app.py +9 -10
  182. autobyteus/cli/workflow_tui/state.py +14 -16
  183. autobyteus/cli/workflow_tui/widgets/agent_list_sidebar.py +15 -15
  184. autobyteus/cli/workflow_tui/widgets/focus_pane.py +137 -35
  185. autobyteus/cli/workflow_tui/widgets/renderables.py +1 -1
  186. autobyteus/cli/workflow_tui/widgets/shared.py +25 -25
  187. autobyteus/clients/autobyteus_client.py +94 -1
  188. autobyteus/events/event_types.py +11 -18
  189. autobyteus/llm/api/autobyteus_llm.py +33 -29
  190. autobyteus/llm/api/claude_llm.py +142 -36
  191. autobyteus/llm/api/gemini_llm.py +163 -59
  192. autobyteus/llm/api/grok_llm.py +1 -1
  193. autobyteus/llm/api/minimax_llm.py +26 -0
  194. autobyteus/llm/api/mistral_llm.py +113 -87
  195. autobyteus/llm/api/ollama_llm.py +9 -42
  196. autobyteus/llm/api/openai_compatible_llm.py +127 -91
  197. autobyteus/llm/api/openai_llm.py +3 -3
  198. autobyteus/llm/api/openai_responses_llm.py +324 -0
  199. autobyteus/llm/api/zhipu_llm.py +21 -2
  200. autobyteus/llm/autobyteus_provider.py +70 -60
  201. autobyteus/llm/base_llm.py +85 -81
  202. autobyteus/llm/converters/__init__.py +14 -0
  203. autobyteus/llm/converters/anthropic_tool_call_converter.py +37 -0
  204. autobyteus/llm/converters/gemini_tool_call_converter.py +57 -0
  205. autobyteus/llm/converters/mistral_tool_call_converter.py +37 -0
  206. autobyteus/llm/converters/openai_tool_call_converter.py +38 -0
  207. autobyteus/llm/extensions/base_extension.py +6 -12
  208. autobyteus/llm/extensions/token_usage_tracking_extension.py +45 -18
  209. autobyteus/llm/llm_factory.py +282 -204
  210. autobyteus/llm/lmstudio_provider.py +60 -49
  211. autobyteus/llm/models.py +35 -2
  212. autobyteus/llm/ollama_provider.py +60 -49
  213. autobyteus/llm/ollama_provider_resolver.py +0 -1
  214. autobyteus/llm/prompt_renderers/__init__.py +19 -0
  215. autobyteus/llm/prompt_renderers/anthropic_prompt_renderer.py +104 -0
  216. autobyteus/llm/prompt_renderers/autobyteus_prompt_renderer.py +19 -0
  217. autobyteus/llm/prompt_renderers/base_prompt_renderer.py +10 -0
  218. autobyteus/llm/prompt_renderers/gemini_prompt_renderer.py +63 -0
  219. autobyteus/llm/prompt_renderers/mistral_prompt_renderer.py +87 -0
  220. autobyteus/llm/prompt_renderers/ollama_prompt_renderer.py +51 -0
  221. autobyteus/llm/prompt_renderers/openai_chat_renderer.py +97 -0
  222. autobyteus/llm/prompt_renderers/openai_responses_renderer.py +101 -0
  223. autobyteus/llm/providers.py +1 -3
  224. autobyteus/llm/token_counter/claude_token_counter.py +56 -25
  225. autobyteus/llm/token_counter/mistral_token_counter.py +12 -8
  226. autobyteus/llm/token_counter/openai_token_counter.py +24 -5
  227. autobyteus/llm/token_counter/token_counter_factory.py +12 -5
  228. autobyteus/llm/utils/llm_config.py +6 -12
  229. autobyteus/llm/utils/media_payload_formatter.py +27 -20
  230. autobyteus/llm/utils/messages.py +55 -3
  231. autobyteus/llm/utils/response_types.py +3 -0
  232. autobyteus/llm/utils/tool_call_delta.py +31 -0
  233. autobyteus/memory/__init__.py +35 -0
  234. autobyteus/memory/compaction/__init__.py +9 -0
  235. autobyteus/memory/compaction/compaction_result.py +8 -0
  236. autobyteus/memory/compaction/compactor.py +89 -0
  237. autobyteus/memory/compaction/summarizer.py +11 -0
  238. autobyteus/memory/compaction_snapshot_builder.py +84 -0
  239. autobyteus/memory/memory_manager.py +205 -0
  240. autobyteus/memory/models/__init__.py +14 -0
  241. autobyteus/memory/models/episodic_item.py +41 -0
  242. autobyteus/memory/models/memory_types.py +7 -0
  243. autobyteus/memory/models/raw_trace_item.py +79 -0
  244. autobyteus/memory/models/semantic_item.py +41 -0
  245. autobyteus/memory/models/tool_interaction.py +20 -0
  246. autobyteus/memory/path_resolver.py +27 -0
  247. autobyteus/memory/policies/__init__.py +5 -0
  248. autobyteus/memory/policies/compaction_policy.py +16 -0
  249. autobyteus/memory/restore/__init__.py +1 -0
  250. autobyteus/memory/restore/working_context_snapshot_bootstrapper.py +61 -0
  251. autobyteus/memory/retrieval/__init__.py +7 -0
  252. autobyteus/memory/retrieval/memory_bundle.py +11 -0
  253. autobyteus/memory/retrieval/retriever.py +13 -0
  254. autobyteus/memory/store/__init__.py +9 -0
  255. autobyteus/memory/store/base_store.py +14 -0
  256. autobyteus/memory/store/file_store.py +98 -0
  257. autobyteus/memory/store/working_context_snapshot_store.py +28 -0
  258. autobyteus/memory/tool_interaction_builder.py +46 -0
  259. autobyteus/memory/turn_tracker.py +9 -0
  260. autobyteus/memory/working_context_snapshot.py +69 -0
  261. autobyteus/memory/working_context_snapshot_serializer.py +135 -0
  262. autobyteus/multimedia/audio/api/autobyteus_audio_client.py +19 -5
  263. autobyteus/multimedia/audio/api/gemini_audio_client.py +109 -16
  264. autobyteus/multimedia/audio/audio_client_factory.py +47 -9
  265. autobyteus/multimedia/audio/audio_model.py +2 -1
  266. autobyteus/multimedia/image/api/autobyteus_image_client.py +19 -5
  267. autobyteus/multimedia/image/api/gemini_image_client.py +39 -17
  268. autobyteus/multimedia/image/api/openai_image_client.py +125 -43
  269. autobyteus/multimedia/image/autobyteus_image_provider.py +2 -1
  270. autobyteus/multimedia/image/image_client_factory.py +47 -15
  271. autobyteus/multimedia/image/image_model.py +5 -2
  272. autobyteus/multimedia/providers.py +3 -2
  273. autobyteus/skills/loader.py +71 -0
  274. autobyteus/skills/model.py +11 -0
  275. autobyteus/skills/registry.py +70 -0
  276. autobyteus/task_management/tools/todo_tools/add_todo.py +2 -2
  277. autobyteus/task_management/tools/todo_tools/create_todo_list.py +2 -2
  278. autobyteus/task_management/tools/todo_tools/update_todo_status.py +2 -2
  279. autobyteus/tools/__init__.py +34 -47
  280. autobyteus/tools/base_tool.py +7 -0
  281. autobyteus/tools/file/__init__.py +2 -6
  282. autobyteus/tools/file/patch_file.py +149 -0
  283. autobyteus/tools/file/read_file.py +36 -5
  284. autobyteus/tools/file/write_file.py +4 -1
  285. autobyteus/tools/functional_tool.py +43 -6
  286. autobyteus/tools/mcp/__init__.py +2 -0
  287. autobyteus/tools/mcp/config_service.py +5 -1
  288. autobyteus/tools/mcp/server/__init__.py +2 -0
  289. autobyteus/tools/mcp/server/http_managed_mcp_server.py +1 -1
  290. autobyteus/tools/mcp/server/websocket_managed_mcp_server.py +141 -0
  291. autobyteus/tools/mcp/server_instance_manager.py +8 -1
  292. autobyteus/tools/mcp/types.py +61 -0
  293. autobyteus/tools/multimedia/audio_tools.py +70 -17
  294. autobyteus/tools/multimedia/download_media_tool.py +18 -4
  295. autobyteus/tools/multimedia/image_tools.py +246 -62
  296. autobyteus/tools/operation_executor/journal_manager.py +107 -0
  297. autobyteus/tools/operation_executor/operation_event_buffer.py +57 -0
  298. autobyteus/tools/operation_executor/operation_event_producer.py +29 -0
  299. autobyteus/tools/operation_executor/operation_executor.py +58 -0
  300. autobyteus/tools/registry/tool_definition.py +43 -2
  301. autobyteus/tools/skill/load_skill.py +50 -0
  302. autobyteus/tools/terminal/__init__.py +45 -0
  303. autobyteus/tools/terminal/ansi_utils.py +32 -0
  304. autobyteus/tools/terminal/background_process_manager.py +233 -0
  305. autobyteus/tools/terminal/output_buffer.py +105 -0
  306. autobyteus/tools/terminal/prompt_detector.py +63 -0
  307. autobyteus/tools/terminal/pty_session.py +241 -0
  308. autobyteus/tools/terminal/session_factory.py +20 -0
  309. autobyteus/tools/terminal/terminal_session_manager.py +226 -0
  310. autobyteus/tools/terminal/tools/__init__.py +13 -0
  311. autobyteus/tools/terminal/tools/get_process_output.py +81 -0
  312. autobyteus/tools/terminal/tools/run_bash.py +109 -0
  313. autobyteus/tools/terminal/tools/start_background_process.py +104 -0
  314. autobyteus/tools/terminal/tools/stop_background_process.py +67 -0
  315. autobyteus/tools/terminal/types.py +54 -0
  316. autobyteus/tools/terminal/wsl_tmux_session.py +221 -0
  317. autobyteus/tools/terminal/wsl_utils.py +156 -0
  318. autobyteus/tools/transaction_management/backup_handler.py +48 -0
  319. autobyteus/tools/transaction_management/operation_lifecycle_manager.py +62 -0
  320. autobyteus/tools/usage/__init__.py +1 -2
  321. autobyteus/tools/usage/formatters/__init__.py +17 -1
  322. autobyteus/tools/usage/formatters/base_formatter.py +8 -0
  323. autobyteus/tools/usage/formatters/default_xml_schema_formatter.py +2 -2
  324. autobyteus/tools/usage/formatters/mistral_json_schema_formatter.py +18 -0
  325. autobyteus/tools/usage/formatters/patch_file_xml_example_formatter.py +64 -0
  326. autobyteus/tools/usage/formatters/patch_file_xml_schema_formatter.py +31 -0
  327. autobyteus/tools/usage/formatters/run_bash_xml_example_formatter.py +32 -0
  328. autobyteus/tools/usage/formatters/run_bash_xml_schema_formatter.py +36 -0
  329. autobyteus/tools/usage/formatters/write_file_xml_example_formatter.py +53 -0
  330. autobyteus/tools/usage/formatters/write_file_xml_schema_formatter.py +31 -0
  331. autobyteus/tools/usage/providers/tool_manifest_provider.py +10 -10
  332. autobyteus/tools/usage/registries/__init__.py +1 -3
  333. autobyteus/tools/usage/registries/tool_formatting_registry.py +115 -8
  334. autobyteus/tools/usage/tool_schema_provider.py +51 -0
  335. autobyteus/tools/web/__init__.py +4 -0
  336. autobyteus/tools/web/read_url_tool.py +80 -0
  337. autobyteus/utils/diff_utils.py +271 -0
  338. autobyteus/utils/download_utils.py +109 -0
  339. autobyteus/utils/file_utils.py +57 -2
  340. autobyteus/utils/gemini_helper.py +64 -0
  341. autobyteus/utils/gemini_model_mapping.py +71 -0
  342. autobyteus/utils/llm_output_formatter.py +75 -0
  343. autobyteus/utils/tool_call_format.py +36 -0
  344. autobyteus/workflow/agentic_workflow.py +3 -3
  345. autobyteus/workflow/bootstrap_steps/agent_tool_injection_step.py +2 -2
  346. autobyteus/workflow/bootstrap_steps/base_workflow_bootstrap_step.py +2 -2
  347. autobyteus/workflow/bootstrap_steps/coordinator_initialization_step.py +2 -2
  348. autobyteus/workflow/bootstrap_steps/coordinator_prompt_preparation_step.py +3 -9
  349. autobyteus/workflow/bootstrap_steps/workflow_bootstrapper.py +6 -6
  350. autobyteus/workflow/bootstrap_steps/workflow_runtime_queue_initialization_step.py +2 -2
  351. autobyteus/workflow/context/workflow_context.py +3 -3
  352. autobyteus/workflow/context/workflow_runtime_state.py +5 -5
  353. autobyteus/workflow/events/workflow_event_dispatcher.py +5 -5
  354. autobyteus/workflow/handlers/lifecycle_workflow_event_handler.py +3 -3
  355. autobyteus/workflow/handlers/process_user_message_event_handler.py +5 -5
  356. autobyteus/workflow/handlers/tool_approval_workflow_event_handler.py +2 -2
  357. autobyteus/workflow/runtime/workflow_runtime.py +8 -8
  358. autobyteus/workflow/runtime/workflow_worker.py +3 -3
  359. autobyteus/workflow/status/__init__.py +11 -0
  360. autobyteus/workflow/status/workflow_status.py +19 -0
  361. autobyteus/workflow/status/workflow_status_manager.py +48 -0
  362. autobyteus/workflow/streaming/__init__.py +2 -2
  363. autobyteus/workflow/streaming/workflow_event_notifier.py +7 -7
  364. autobyteus/workflow/streaming/workflow_stream_event_payloads.py +4 -4
  365. autobyteus/workflow/streaming/workflow_stream_events.py +3 -3
  366. autobyteus/workflow/utils/wait_for_idle.py +4 -4
  367. autobyteus-1.3.0.dist-info/METADATA +293 -0
  368. autobyteus-1.3.0.dist-info/RECORD +606 -0
  369. {autobyteus-1.2.1.dist-info → autobyteus-1.3.0.dist-info}/WHEEL +1 -1
  370. {autobyteus-1.2.1.dist-info → autobyteus-1.3.0.dist-info}/top_level.txt +0 -1
  371. autobyteus/agent/bootstrap_steps/agent_runtime_queue_initialization_step.py +0 -57
  372. autobyteus/agent/hooks/__init__.py +0 -16
  373. autobyteus/agent/hooks/base_phase_hook.py +0 -78
  374. autobyteus/agent/hooks/hook_definition.py +0 -36
  375. autobyteus/agent/hooks/hook_meta.py +0 -37
  376. autobyteus/agent/hooks/hook_registry.py +0 -106
  377. autobyteus/agent/llm_response_processor/provider_aware_tool_usage_processor.py +0 -103
  378. autobyteus/agent/phases/__init__.py +0 -18
  379. autobyteus/agent/phases/discover.py +0 -53
  380. autobyteus/agent/phases/manager.py +0 -265
  381. autobyteus/agent/phases/transition_decorator.py +0 -40
  382. autobyteus/agent/phases/transition_info.py +0 -33
  383. autobyteus/agent/remote_agent.py +0 -244
  384. autobyteus/agent/workspace/workspace_definition.py +0 -36
  385. autobyteus/agent/workspace/workspace_meta.py +0 -37
  386. autobyteus/agent/workspace/workspace_registry.py +0 -72
  387. autobyteus/agent_team/bootstrap_steps/agent_team_runtime_queue_initialization_step.py +0 -25
  388. autobyteus/agent_team/bootstrap_steps/coordinator_prompt_preparation_step.py +0 -85
  389. autobyteus/agent_team/phases/__init__.py +0 -11
  390. autobyteus/agent_team/phases/agent_team_operational_phase.py +0 -19
  391. autobyteus/agent_team/phases/agent_team_phase_manager.py +0 -48
  392. autobyteus/llm/api/bedrock_llm.py +0 -92
  393. autobyteus/llm/api/groq_llm.py +0 -94
  394. autobyteus/llm/api/nvidia_llm.py +0 -108
  395. autobyteus/llm/utils/token_pricing_config.py +0 -87
  396. autobyteus/rpc/__init__.py +0 -73
  397. autobyteus/rpc/client/__init__.py +0 -17
  398. autobyteus/rpc/client/abstract_client_connection.py +0 -124
  399. autobyteus/rpc/client/client_connection_manager.py +0 -153
  400. autobyteus/rpc/client/sse_client_connection.py +0 -306
  401. autobyteus/rpc/client/stdio_client_connection.py +0 -280
  402. autobyteus/rpc/config/__init__.py +0 -13
  403. autobyteus/rpc/config/agent_server_config.py +0 -153
  404. autobyteus/rpc/config/agent_server_registry.py +0 -152
  405. autobyteus/rpc/hosting.py +0 -244
  406. autobyteus/rpc/protocol.py +0 -244
  407. autobyteus/rpc/server/__init__.py +0 -20
  408. autobyteus/rpc/server/agent_server_endpoint.py +0 -181
  409. autobyteus/rpc/server/base_method_handler.py +0 -40
  410. autobyteus/rpc/server/method_handlers.py +0 -259
  411. autobyteus/rpc/server/sse_server_handler.py +0 -182
  412. autobyteus/rpc/server/stdio_server_handler.py +0 -151
  413. autobyteus/rpc/server_main.py +0 -198
  414. autobyteus/rpc/transport_type.py +0 -13
  415. autobyteus/tools/bash/__init__.py +0 -2
  416. autobyteus/tools/bash/bash_executor.py +0 -100
  417. autobyteus/tools/browser/__init__.py +0 -2
  418. autobyteus/tools/browser/session_aware/browser_session_aware_navigate_to.py +0 -75
  419. autobyteus/tools/browser/session_aware/browser_session_aware_tool.py +0 -30
  420. autobyteus/tools/browser/session_aware/browser_session_aware_web_element_trigger.py +0 -154
  421. autobyteus/tools/browser/session_aware/browser_session_aware_webpage_reader.py +0 -89
  422. autobyteus/tools/browser/session_aware/browser_session_aware_webpage_screenshot_taker.py +0 -107
  423. autobyteus/tools/browser/session_aware/factory/browser_session_aware_web_element_trigger_factory.py +0 -14
  424. autobyteus/tools/browser/session_aware/factory/browser_session_aware_webpage_reader_factory.py +0 -26
  425. autobyteus/tools/browser/session_aware/factory/browser_session_aware_webpage_screenshot_taker_factory.py +0 -14
  426. autobyteus/tools/browser/session_aware/shared_browser_session.py +0 -11
  427. autobyteus/tools/browser/session_aware/shared_browser_session_manager.py +0 -25
  428. autobyteus/tools/browser/session_aware/web_element_action.py +0 -20
  429. autobyteus/tools/browser/standalone/__init__.py +0 -6
  430. autobyteus/tools/browser/standalone/factory/__init__.py +0 -0
  431. autobyteus/tools/browser/standalone/factory/webpage_reader_factory.py +0 -25
  432. autobyteus/tools/browser/standalone/factory/webpage_screenshot_taker_factory.py +0 -14
  433. autobyteus/tools/browser/standalone/navigate_to.py +0 -84
  434. autobyteus/tools/browser/standalone/web_page_pdf_generator.py +0 -101
  435. autobyteus/tools/browser/standalone/webpage_image_downloader.py +0 -169
  436. autobyteus/tools/browser/standalone/webpage_reader.py +0 -105
  437. autobyteus/tools/browser/standalone/webpage_screenshot_taker.py +0 -105
  438. autobyteus/tools/file/edit_file.py +0 -200
  439. autobyteus/tools/file/list_directory.py +0 -168
  440. autobyteus/tools/file/search_files.py +0 -188
  441. autobyteus/tools/timer.py +0 -175
  442. autobyteus/tools/usage/parsers/__init__.py +0 -22
  443. autobyteus/tools/usage/parsers/_json_extractor.py +0 -99
  444. autobyteus/tools/usage/parsers/_string_decoders.py +0 -18
  445. autobyteus/tools/usage/parsers/anthropic_xml_tool_usage_parser.py +0 -10
  446. autobyteus/tools/usage/parsers/base_parser.py +0 -41
  447. autobyteus/tools/usage/parsers/default_json_tool_usage_parser.py +0 -83
  448. autobyteus/tools/usage/parsers/default_xml_tool_usage_parser.py +0 -316
  449. autobyteus/tools/usage/parsers/exceptions.py +0 -13
  450. autobyteus/tools/usage/parsers/gemini_json_tool_usage_parser.py +0 -77
  451. autobyteus/tools/usage/parsers/openai_json_tool_usage_parser.py +0 -149
  452. autobyteus/tools/usage/parsers/provider_aware_tool_usage_parser.py +0 -59
  453. autobyteus/tools/usage/registries/tool_usage_parser_registry.py +0 -62
  454. autobyteus/workflow/phases/__init__.py +0 -11
  455. autobyteus/workflow/phases/workflow_operational_phase.py +0 -19
  456. autobyteus/workflow/phases/workflow_phase_manager.py +0 -48
  457. autobyteus-1.2.1.dist-info/METADATA +0 -205
  458. autobyteus-1.2.1.dist-info/RECORD +0 -511
  459. examples/__init__.py +0 -1
  460. examples/agent_team/__init__.py +0 -1
  461. examples/discover_phase_transitions.py +0 -104
  462. examples/run_agentic_software_engineer.py +0 -239
  463. examples/run_browser_agent.py +0 -262
  464. examples/run_google_slides_agent.py +0 -287
  465. examples/run_mcp_browser_client.py +0 -174
  466. examples/run_mcp_google_slides_client.py +0 -270
  467. examples/run_mcp_list_tools.py +0 -189
  468. examples/run_poem_writer.py +0 -284
  469. examples/run_sqlite_agent.py +0 -295
  470. /autobyteus/{tools/browser/session_aware → skills}/__init__.py +0 -0
  471. /autobyteus/tools/{browser/session_aware/factory → skill}/__init__.py +0 -0
  472. {autobyteus-1.2.1.dist-info → autobyteus-1.3.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,200 +0,0 @@
1
- import os
2
- import re
3
- import logging
4
- from typing import TYPE_CHECKING, List
5
-
6
- from autobyteus.tools.functional_tool import tool
7
- from autobyteus.tools.tool_category import ToolCategory
8
-
9
- if TYPE_CHECKING:
10
- from autobyteus.agent.context import AgentContext
11
-
12
- logger = logging.getLogger(__name__)
13
-
14
- _HUNK_HEADER_RE = re.compile(r"^@@ -(?P<old_start>\d+)(?:,(?P<old_count>\d+))? \+(?P<new_start>\d+)(?:,(?P<new_count>\d+))? @@")
15
-
16
- class PatchApplicationError(ValueError):
17
- """Raised when a unified diff patch cannot be applied to the target file."""
18
-
19
-
20
- def _resolve_file_path(context: 'AgentContext', path: str) -> str:
21
- """Resolves an absolute path for the given input, using the agent workspace when needed."""
22
- if os.path.isabs(path):
23
- final_path = path
24
- logger.debug("edit_file: provided path '%s' is absolute.", path)
25
- else:
26
- if not context.workspace:
27
- error_msg = ("Relative path '%s' provided, but no workspace is configured for agent '%s'. "
28
- "A workspace is required to resolve relative paths.")
29
- logger.error(error_msg, path, context.agent_id)
30
- raise ValueError(error_msg % (path, context.agent_id))
31
- base_path = context.workspace.get_base_path()
32
- if not base_path or not isinstance(base_path, str):
33
- error_msg = ("Agent '%s' has a configured workspace, but it provided an invalid base path ('%s'). "
34
- "Cannot resolve relative path '%s'.")
35
- logger.error(error_msg, context.agent_id, base_path, path)
36
- raise ValueError(error_msg % (context.agent_id, base_path, path))
37
- final_path = os.path.join(base_path, path)
38
- logger.debug("edit_file: resolved relative path '%s' against workspace base '%s' to '%s'.", path, base_path, final_path)
39
-
40
- normalized_path = os.path.normpath(final_path)
41
- logger.debug("edit_file: normalized path to '%s'.", normalized_path)
42
- return normalized_path
43
-
44
-
45
- def _apply_unified_diff(original_lines: List[str], patch: str) -> List[str]:
46
- """Applies a unified diff patch to the provided original lines and returns the patched lines."""
47
- if not patch or not patch.strip():
48
- raise PatchApplicationError("Patch content is empty; nothing to apply.")
49
-
50
- patched_lines: List[str] = []
51
- orig_idx = 0
52
- patch_lines = patch.splitlines(keepends=True)
53
- line_idx = 0
54
-
55
- while line_idx < len(patch_lines):
56
- line = patch_lines[line_idx]
57
-
58
- if line.startswith('---') or line.startswith('+++'):
59
- logger.debug("edit_file: skipping diff header line '%s'.", line.strip())
60
- line_idx += 1
61
- continue
62
-
63
- if not line.startswith('@@'):
64
- stripped = line.strip()
65
- if stripped == '':
66
- line_idx += 1
67
- continue
68
- raise PatchApplicationError(f"Unexpected content outside of hunk header: '{stripped}'.")
69
-
70
- match = _HUNK_HEADER_RE.match(line)
71
- if not match:
72
- raise PatchApplicationError(f"Malformed hunk header: '{line.strip()}'.")
73
-
74
- old_start = int(match.group('old_start'))
75
- old_count = int(match.group('old_count') or '1')
76
- new_start = int(match.group('new_start'))
77
- new_count = int(match.group('new_count') or '1')
78
- logger.debug("edit_file: processing hunk old_start=%s old_count=%s new_start=%s new_count=%s.",
79
- old_start, old_count, new_start, new_count)
80
-
81
- target_idx = old_start - 1 if old_start > 0 else 0
82
- if target_idx > len(original_lines):
83
- raise PatchApplicationError("Patch hunk starts beyond end of file.")
84
- if target_idx < orig_idx:
85
- raise PatchApplicationError("Patch hunks overlap or are out of order.")
86
-
87
- patched_lines.extend(original_lines[orig_idx:target_idx])
88
- orig_idx = target_idx
89
-
90
- line_idx += 1
91
- hunk_consumed = 0
92
- removed = 0
93
- added = 0
94
-
95
- while line_idx < len(patch_lines):
96
- hunk_line = patch_lines[line_idx]
97
- if hunk_line.startswith('@@'):
98
- break
99
-
100
- if hunk_line.startswith('-'):
101
- if orig_idx >= len(original_lines):
102
- raise PatchApplicationError("Patch attempts to remove lines beyond file length.")
103
- if original_lines[orig_idx] != hunk_line[1:]:
104
- raise PatchApplicationError("Patch removal does not match file content.")
105
- orig_idx += 1
106
- hunk_consumed += 1
107
- removed += 1
108
- elif hunk_line.startswith('+'):
109
- patched_lines.append(hunk_line[1:])
110
- added += 1
111
- elif hunk_line.startswith(' '):
112
- if orig_idx >= len(original_lines):
113
- raise PatchApplicationError("Patch context exceeds file length.")
114
- if original_lines[orig_idx] != hunk_line[1:]:
115
- raise PatchApplicationError("Patch context does not match file content.")
116
- patched_lines.append(original_lines[orig_idx])
117
- orig_idx += 1
118
- hunk_consumed += 1
119
- elif hunk_line.startswith('\\'):
120
- if hunk_line.strip() == '\':
121
- if patched_lines:
122
- patched_lines[-1] = patched_lines[-1].rstrip('\n')
123
- else:
124
- raise PatchApplicationError(f"Unsupported patch directive: '{hunk_line.strip()}'.")
125
- elif hunk_line.strip() == '':
126
- patched_lines.append(hunk_line)
127
- else:
128
- raise PatchApplicationError(f"Unsupported patch line: '{hunk_line.strip()}'.")
129
-
130
- line_idx += 1
131
-
132
- consumed_total = hunk_consumed
133
- if old_count == 0:
134
- if consumed_total != 0:
135
- raise PatchApplicationError("Patch expects zero original lines but consumed some context.")
136
- else:
137
- if consumed_total != old_count:
138
- raise PatchApplicationError(
139
- f"Patch expected to consume {old_count} original lines but consumed {consumed_total}.")
140
-
141
- context_lines = consumed_total - removed
142
- expected_new_lines = context_lines + added
143
- if new_count == 0:
144
- if expected_new_lines != 0:
145
- raise PatchApplicationError("Patch declares zero new lines but produced changes.")
146
- else:
147
- if expected_new_lines != new_count:
148
- raise PatchApplicationError(
149
- f"Patch expected to produce {new_count} new lines but produced {expected_new_lines}.")
150
-
151
- patched_lines.extend(original_lines[orig_idx:])
152
- return patched_lines
153
-
154
-
155
- @tool(name="edit_file", category=ToolCategory.FILE_SYSTEM)
156
- async def edit_file(context: 'AgentContext', path: str, patch: str, create_if_missing: bool = False) -> str:
157
- """Applies a unified diff patch to update a text file without overwriting unrelated content.
158
-
159
- Args:
160
- path: Path to the target file. Relative paths are resolved against the agent workspace when available.
161
- patch: Unified diff patch describing the edits to apply.
162
- create_if_missing: When True, allows applying a patch that introduces content to a non-existent file.
163
-
164
- Raises:
165
- FileNotFoundError: If the file does not exist and create_if_missing is False.
166
- PatchApplicationError: If the patch content cannot be applied cleanly.
167
- IOError: If file reading or writing fails.
168
- """
169
- logger.debug("edit_file: requested edit for agent '%s' on path '%s'.", context.agent_id, path)
170
- final_path = _resolve_file_path(context, path)
171
-
172
- dir_path = os.path.dirname(final_path)
173
- if dir_path and not os.path.exists(dir_path) and create_if_missing:
174
- os.makedirs(dir_path, exist_ok=True)
175
-
176
- file_exists = os.path.exists(final_path)
177
- if not file_exists and not create_if_missing:
178
- raise FileNotFoundError(f"The file at resolved path {final_path} does not exist.")
179
-
180
- try:
181
- original_lines: List[str]
182
- if file_exists:
183
- with open(final_path, 'r', encoding='utf-8') as source:
184
- original_lines = source.read().splitlines(keepends=True)
185
- else:
186
- original_lines = []
187
-
188
- patched_lines = _apply_unified_diff(original_lines, patch)
189
-
190
- with open(final_path, 'w', encoding='utf-8') as destination:
191
- destination.writelines(patched_lines)
192
-
193
- logger.info("edit_file: successfully applied patch to '%s'.", final_path)
194
- return f"File edited successfully at {final_path}"
195
- except PatchApplicationError as patch_err:
196
- logger.error("edit_file: failed to apply patch to '%s': %s", final_path, patch_err, exc_info=True)
197
- raise patch_err
198
- except Exception as exc: # pragma: no cover - general safeguard
199
- logger.error("edit_file: unexpected error while editing '%s': %s", final_path, exc, exc_info=True)
200
- raise IOError(f"Could not edit file at '{final_path}': {exc}")
@@ -1,168 +0,0 @@
1
- # file: autobyteus/autobyteus/tools/file/list_directory.py
2
- """
3
- This module provides a tool for listing directory contents in a structured,
4
- tree-like format, mirroring the behavior of the Codex Rust implementation.
5
- """
6
-
7
- import asyncio
8
- import logging
9
- import os
10
- from pathlib import Path
11
- from collections import deque
12
- from dataclasses import dataclass
13
- from typing import List, Deque, Tuple, Optional, TYPE_CHECKING
14
-
15
- from autobyteus.tools.functional_tool import tool
16
- from autobyteus.tools.tool_category import ToolCategory
17
-
18
- if TYPE_CHECKING:
19
- from autobyteus.agent.context import AgentContext
20
-
21
- logger = logging.getLogger(__name__)
22
-
23
- # Constants from the design document
24
- INDENTATION_SPACES = 2
25
- MAX_ENTRY_LENGTH = 500
26
-
27
- @dataclass
28
- class DirEntry:
29
- """Represents a collected directory entry for sorting and formatting."""
30
- name: str
31
- kind: str
32
- depth: int
33
-
34
- @tool(name="list_directory", category=ToolCategory.FILE_SYSTEM)
35
- async def list_directory(
36
- context: 'AgentContext',
37
- path: str,
38
- depth: int = 2,
39
- limit: int = 25,
40
- offset: int = 1
41
- ) -> str:
42
- """
43
- Lists the contents of a directory in a structured, tree-like format.
44
-
45
- This tool performs a breadth-first traversal of the specified directory up to a
46
- given depth. It returns a deterministic, lexicographically sorted list of entries,
47
- formatted with indentation and tree glyphs to represent the hierarchy.
48
-
49
- Args:
50
- path: The path to the directory to list. Relative paths are resolved against the agent's workspace.
51
- depth: The maximum directory depth to traverse. Must be > 0.
52
- limit: The maximum number of entries to return in the output. Must be > 0.
53
- offset: The 1-indexed entry number to start from, for pagination. Must be > 0.
54
- """
55
- # --- 1. Argument Validation ---
56
- logger.debug(f"list_directory for agent {context.agent_id}, initial path: {path}")
57
-
58
- final_path: str
59
- if os.path.isabs(path):
60
- final_path = path
61
- logger.debug(f"Path '{path}' is absolute. Using it directly.")
62
- else:
63
- if not context.workspace:
64
- error_msg = f"Relative path '{path}' provided, but no workspace is configured for agent '{context.agent_id}'. A workspace is required to resolve relative paths."
65
- logger.error(error_msg)
66
- raise ValueError(error_msg)
67
-
68
- base_path = context.workspace.get_base_path()
69
- if not base_path or not isinstance(base_path, str):
70
- error_msg = f"Agent '{context.agent_id}' has a configured workspace, but it provided an invalid base path ('{base_path}'). Cannot resolve relative path '{path}'."
71
- logger.error(error_msg)
72
- raise ValueError(error_msg)
73
-
74
- final_path = os.path.join(base_path, path)
75
- logger.debug(f"Path '{path}' is relative. Resolved to '{final_path}' using workspace base path '{base_path}'.")
76
-
77
- final_path = os.path.normpath(final_path)
78
-
79
- if not Path(final_path).is_dir():
80
- raise FileNotFoundError(f"Directory not found at path: {final_path}")
81
- if depth <= 0 or limit <= 0 or offset <= 0:
82
- raise ValueError("depth, limit, and offset must all be greater than zero.")
83
-
84
- # --- 2. Asynchronous Traversal ---
85
- loop = asyncio.get_running_loop()
86
- all_entries = await loop.run_in_executor(
87
- None, _traverse_directory_bfs, Path(final_path), depth
88
- )
89
-
90
- # --- 3. Slicing ---
91
- total_found = len(all_entries)
92
- start_index = offset - 1
93
- end_index = start_index + limit
94
- sliced_entries = all_entries[start_index:end_index]
95
-
96
- # --- 4. Formatting ---
97
- output_lines = [f"Absolute path: {final_path}"]
98
-
99
- # To correctly apply tree glyphs, we need to know which entry is the last in its directory
100
- # This is complex with BFS. A simpler, visually acceptable approach is taken here.
101
- # For a more accurate glyph representation like the Rust version, we would need to
102
- # process entries directory by directory after collection.
103
- for i, entry in enumerate(sliced_entries):
104
- # A simplified glyph logic: last item in the slice gets the closing glyph
105
- is_last = (i == len(sliced_entries) - 1)
106
- output_lines.append(_format_entry_line(entry, is_last))
107
-
108
- if total_found > end_index:
109
- output_lines.append(f"More than {limit} entries found.")
110
-
111
- return "\n".join(output_lines)
112
-
113
-
114
- def _traverse_directory_bfs(start_path: Path, max_depth: int) -> List[DirEntry]:
115
- """
116
- Performs a breadth-first traversal of a directory. This is a synchronous function
117
- designed to be run in a thread pool executor.
118
- """
119
- collected: List[DirEntry] = []
120
- queue: Deque[Tuple[Path, int]] = deque([(start_path, 0)])
121
-
122
- while queue:
123
- current_path, current_depth = queue.popleft()
124
-
125
- if current_depth >= max_depth:
126
- continue
127
-
128
- try:
129
- # Use os.scandir for efficiency as it fetches file type info
130
- entries_at_level = []
131
- for entry in os.scandir(current_path):
132
- kind = "[unknown]"
133
- if entry.is_dir():
134
- kind = "[dir]"
135
- queue.append((Path(entry.path), current_depth + 1))
136
- elif entry.is_file():
137
- kind = "[file]"
138
- elif entry.is_symlink():
139
- kind = "[link]"
140
-
141
- # Truncate long filenames
142
- display_name = entry.name
143
- if len(display_name) > MAX_ENTRY_LENGTH:
144
- display_name = display_name[:MAX_ENTRY_LENGTH] + "..."
145
-
146
- entries_at_level.append(DirEntry(name=display_name, kind=kind, depth=current_depth + 1))
147
-
148
- # Sort entries at the current level before adding to the main list
149
- entries_at_level.sort(key=lambda e: e.name)
150
- collected.extend(entries_at_level)
151
-
152
- except (PermissionError, OSError) as e:
153
- logger.warning(f"Could not read directory '{current_path}': {e}")
154
- continue
155
-
156
- return collected
157
-
158
-
159
- def _format_entry_line(entry: DirEntry, is_last_in_slice: bool) -> str:
160
- """Formats a single directory entry into its final string representation."""
161
- # This simplified glyph logic doesn't know about siblings, just the slice.
162
- # A full implementation would require grouping by parent path after collection.
163
- prefix = "└─ " if is_last_in_slice else "├─ "
164
-
165
- # Indentation is based on depth from the root search path
166
- indentation = " " * INDENTATION_SPACES * (entry.depth -1)
167
-
168
- return f"{indentation}{prefix}{entry.kind} {entry.name}"
@@ -1,188 +0,0 @@
1
- # file: autobyteus/autobyteus/tools/file/search_files.py
2
- """
3
- This module provides a high-performance fuzzy file search tool.
4
- It uses 'git ls-files' for speed in Git repositories and falls back
5
- to a filesystem walk for other directories, respecting .gitignore.
6
- """
7
-
8
- import asyncio
9
- import json
10
- import logging
11
- import os
12
- import subprocess
13
- from pathlib import Path
14
- from typing import List, Dict, Optional, Tuple, TYPE_CHECKING
15
-
16
- from rapidfuzz import process, fuzz
17
- from pathspec import PathSpec
18
- from pathspec.patterns import GitWildMatchPattern
19
-
20
- from autobyteus.tools.functional_tool import tool
21
- from autobyteus.tools.tool_category import ToolCategory
22
-
23
- if TYPE_CHECKING:
24
- from autobyteus.agent.context import AgentContext
25
-
26
- logger = logging.getLogger(__name__)
27
-
28
-
29
- @tool(name="search_files", category=ToolCategory.FILE_SYSTEM)
30
- async def search_files(
31
- context: 'AgentContext',
32
- query: Optional[str] = None,
33
- path: str = '.',
34
- limit: int = 64,
35
- exclude_patterns: Optional[List[str]] = None
36
- ) -> str:
37
- """
38
- Performs a high-performance fuzzy search for files in a directory.
39
-
40
- This tool intelligently discovers files. If the search directory is a Git repository,
41
- it uses the highly efficient 'git ls-files' command. Otherwise, it performs a
42
- standard filesystem walk. In both cases, it respects .gitignore rules and any
43
- additional exclusion patterns provided. The search results are returned as a
44
- JSON string, with each result including the file path and a relevance score.
45
-
46
- Args:
47
- query: The fuzzy search pattern. If omitted, the tool lists all discoverable files up to the limit.
48
- path: The directory to search in. Relative paths are resolved against the agent's workspace. Defaults to the workspace root.
49
- limit: The maximum number of results to return.
50
- exclude_patterns: A list of glob patterns to exclude from the search, in addition to .gitignore rules.
51
- """
52
- final_path = _resolve_search_path(context, path)
53
- if not final_path.is_dir():
54
- raise FileNotFoundError(f"The specified search path does not exist or is not a directory: {final_path}")
55
-
56
- exclude = exclude_patterns or []
57
- files, discovery_method = await _discover_files(final_path, exclude)
58
-
59
- if not query:
60
- # If no query, just return the first 'limit' files found
61
- matches = [{"path": f, "score": 100} for f in files[:limit]]
62
- result_summary = {
63
- "discovery_method": discovery_method,
64
- "total_files_scanned": len(files),
65
- "matches_found": len(matches),
66
- "results": matches
67
- }
68
- return json.dumps(result_summary, indent=2)
69
-
70
- # Use rapidfuzz to find the best matches
71
- results = process.extract(
72
- query,
73
- files,
74
- scorer=fuzz.WRatio,
75
- limit=limit,
76
- score_cutoff=50
77
- )
78
-
79
- file_matches = [{"path": path, "score": round(score)} for path, score, _ in results]
80
-
81
- result_summary = {
82
- "discovery_method": discovery_method,
83
- "total_files_scanned": len(files),
84
- "matches_found": len(file_matches),
85
- "results": file_matches
86
- }
87
- return json.dumps(result_summary, indent=2)
88
-
89
-
90
- def _resolve_search_path(context: 'AgentContext', path: str) -> Path:
91
- """Resolves the search path against the agent's workspace if relative."""
92
- if os.path.isabs(path):
93
- return Path(path)
94
-
95
- if not context.workspace:
96
- raise ValueError(f"Relative path '{path}' provided, but no workspace is configured for agent '{context.agent_id}'.")
97
-
98
- base_path = context.workspace.get_base_path()
99
- if not base_path:
100
- raise ValueError(f"Agent '{context.agent_id}' has a workspace, but it provided an invalid base path.")
101
-
102
- return Path(os.path.normpath(os.path.join(base_path, path)))
103
-
104
-
105
- async def _is_git_repository_async(path: Path) -> bool:
106
- """Asynchronously checks if a given path is within a Git repository."""
107
- process = await asyncio.create_subprocess_exec(
108
- "git", "rev-parse", "--is-inside-work-tree",
109
- cwd=str(path),
110
- stdout=asyncio.subprocess.PIPE,
111
- stderr=asyncio.subprocess.PIPE,
112
- )
113
- stdout, _ = await process.communicate()
114
- return stdout.decode().strip() == "true"
115
-
116
-
117
- async def _get_files_from_git_async(path: Path) -> List[str]:
118
- """Uses 'git ls-files' to get a list of all tracked and untracked files."""
119
- try:
120
- process = await asyncio.create_subprocess_exec(
121
- "git", "ls-files", "-co", "--exclude-standard",
122
- cwd=str(path),
123
- stdout=asyncio.subprocess.PIPE,
124
- stderr=asyncio.subprocess.PIPE,
125
- )
126
- stdout_bytes, stderr_bytes = await process.communicate()
127
- if process.returncode != 0:
128
- stderr = stderr_bytes.decode().strip()
129
- logger.error(f"Failed to run 'git ls-files' in '{path}': {stderr}")
130
- return []
131
-
132
- stdout = stdout_bytes.decode().strip()
133
- return stdout.strip().split("\n") if stdout.strip() else []
134
- except (subprocess.CalledProcessError, FileNotFoundError) as e:
135
- logger.error(f"Failed to run 'git ls-files': {e}")
136
- return []
137
-
138
-
139
- def _get_files_with_walk_sync(path: Path, exclude_patterns: List[str]) -> List[str]:
140
- """Synchronously walks the filesystem to find files, respecting ignore patterns."""
141
- files: List[str] = []
142
-
143
- all_exclude_patterns = exclude_patterns[:]
144
- gitignore_path = path / ".gitignore"
145
- if gitignore_path.is_file():
146
- try:
147
- with open(gitignore_path, "r", encoding='utf-8') as f:
148
- all_exclude_patterns.extend(f.read().splitlines())
149
- except Exception as e:
150
- logger.warning(f"Could not read .gitignore file at '{gitignore_path}': {e}")
151
-
152
- spec = PathSpec.from_lines(GitWildMatchPattern, all_exclude_patterns)
153
-
154
- for root, _, filenames in os.walk(path, topdown=True):
155
- root_path = Path(root)
156
- for filename in filenames:
157
- full_path = root_path / filename
158
- try:
159
- relative_path = full_path.relative_to(path)
160
- if not spec.match_file(str(relative_path)):
161
- files.append(str(relative_path))
162
- except (ValueError, IsADirectoryError):
163
- # Handles cases like broken symlinks
164
- continue
165
- return files
166
-
167
-
168
- async def _get_files_with_walk_async(path: Path, exclude_patterns: List[str]) -> List[str]:
169
- """Runs the synchronous walk in a thread pool."""
170
- loop = asyncio.get_running_loop()
171
- return await loop.run_in_executor(
172
- None, _get_files_with_walk_sync, path, exclude_patterns
173
- )
174
-
175
-
176
- async def _discover_files(cwd: Path, exclude: List[str]) -> Tuple[List[str], str]:
177
- """Orchestrates the file discovery, choosing between Git and os.walk."""
178
- if await _is_git_repository_async(cwd):
179
- logger.info(f"Using 'git ls-files' for fast file discovery in '{cwd}'.")
180
- files = await _get_files_from_git_async(cwd)
181
- # Git ls-files already handles gitignore, but we may have extra excludes
182
- if exclude:
183
- spec = PathSpec.from_lines(GitWildMatchPattern, exclude)
184
- files = [f for f in files if not spec.match_file(f)]
185
- return files, "git"
186
- else:
187
- logger.info(f"Using 'os.walk' to scan directory '{cwd}'.")
188
- return await _get_files_with_walk_async(cwd, exclude), "os_walk"