autobyteus 1.2.0__py3-none-any.whl → 1.2.3__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 (512) hide show
  1. autobyteus/agent/agent.py +15 -5
  2. autobyteus/agent/bootstrap_steps/__init__.py +1 -3
  3. autobyteus/agent/bootstrap_steps/agent_bootstrapper.py +3 -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/workspace_context_initialization_step.py +2 -4
  8. autobyteus/agent/context/agent_config.py +43 -20
  9. autobyteus/agent/context/agent_context.py +23 -18
  10. autobyteus/agent/context/agent_runtime_state.py +23 -19
  11. autobyteus/agent/events/__init__.py +16 -1
  12. autobyteus/agent/events/agent_events.py +43 -3
  13. autobyteus/agent/events/agent_input_event_queue_manager.py +79 -26
  14. autobyteus/agent/events/event_store.py +57 -0
  15. autobyteus/agent/events/notifiers.py +74 -60
  16. autobyteus/agent/events/worker_event_dispatcher.py +21 -64
  17. autobyteus/agent/factory/agent_factory.py +52 -0
  18. autobyteus/agent/handlers/__init__.py +2 -0
  19. autobyteus/agent/handlers/approved_tool_invocation_event_handler.py +51 -34
  20. autobyteus/agent/handlers/bootstrap_event_handler.py +155 -0
  21. autobyteus/agent/handlers/inter_agent_message_event_handler.py +10 -0
  22. autobyteus/agent/handlers/lifecycle_event_logger.py +19 -11
  23. autobyteus/agent/handlers/llm_complete_response_received_event_handler.py +10 -15
  24. autobyteus/agent/handlers/llm_user_message_ready_event_handler.py +188 -48
  25. autobyteus/agent/handlers/tool_execution_approval_event_handler.py +0 -10
  26. autobyteus/agent/handlers/tool_invocation_request_event_handler.py +53 -48
  27. autobyteus/agent/handlers/tool_result_event_handler.py +7 -8
  28. autobyteus/agent/handlers/user_input_message_event_handler.py +10 -3
  29. autobyteus/agent/input_processor/memory_ingest_input_processor.py +40 -0
  30. autobyteus/agent/lifecycle/__init__.py +12 -0
  31. autobyteus/agent/lifecycle/base_processor.py +109 -0
  32. autobyteus/agent/lifecycle/events.py +35 -0
  33. autobyteus/agent/lifecycle/processor_definition.py +36 -0
  34. autobyteus/agent/lifecycle/processor_registry.py +106 -0
  35. autobyteus/agent/llm_request_assembler.py +98 -0
  36. autobyteus/agent/llm_response_processor/__init__.py +1 -8
  37. autobyteus/agent/message/context_file_type.py +1 -1
  38. autobyteus/agent/message/send_message_to.py +5 -4
  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 -178
  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 +81 -0
  114. autobyteus/agent/streaming/stream_event_payloads.py +2 -198
  115. autobyteus/agent/streaming/stream_events.py +3 -128
  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 +5 -6
  145. autobyteus/agent_team/bootstrap_steps/team_context_initialization_step.py +15 -15
  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 +11 -8
  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 +10 -10
  167. autobyteus/agent_team/streaming/agent_team_stream_event_payloads.py +7 -7
  168. autobyteus/agent_team/streaming/agent_team_stream_events.py +11 -11
  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/activation_policy.py +1 -1
  172. autobyteus/agent_team/task_notification/system_event_driven_agent_task_notifier.py +22 -22
  173. autobyteus/agent_team/task_notification/task_notification_mode.py +20 -1
  174. autobyteus/agent_team/utils/wait_for_idle.py +4 -4
  175. autobyteus/cli/agent_cli.py +18 -10
  176. autobyteus/cli/agent_team_tui/app.py +18 -15
  177. autobyteus/cli/agent_team_tui/state.py +21 -23
  178. autobyteus/cli/agent_team_tui/widgets/agent_list_sidebar.py +15 -15
  179. autobyteus/cli/agent_team_tui/widgets/focus_pane.py +146 -39
  180. autobyteus/cli/agent_team_tui/widgets/renderables.py +1 -1
  181. autobyteus/cli/agent_team_tui/widgets/shared.py +26 -26
  182. autobyteus/cli/agent_team_tui/widgets/{task_board_panel.py → task_plan_panel.py} +5 -5
  183. autobyteus/cli/cli_display.py +193 -44
  184. autobyteus/cli/workflow_tui/app.py +9 -10
  185. autobyteus/cli/workflow_tui/state.py +14 -16
  186. autobyteus/cli/workflow_tui/widgets/agent_list_sidebar.py +15 -15
  187. autobyteus/cli/workflow_tui/widgets/focus_pane.py +137 -35
  188. autobyteus/cli/workflow_tui/widgets/renderables.py +1 -1
  189. autobyteus/cli/workflow_tui/widgets/shared.py +25 -25
  190. autobyteus/clients/autobyteus_client.py +94 -1
  191. autobyteus/events/event_types.py +15 -21
  192. autobyteus/llm/api/autobyteus_llm.py +33 -29
  193. autobyteus/llm/api/claude_llm.py +142 -36
  194. autobyteus/llm/api/gemini_llm.py +163 -59
  195. autobyteus/llm/api/grok_llm.py +1 -1
  196. autobyteus/llm/api/minimax_llm.py +26 -0
  197. autobyteus/llm/api/mistral_llm.py +113 -87
  198. autobyteus/llm/api/ollama_llm.py +9 -42
  199. autobyteus/llm/api/openai_compatible_llm.py +127 -91
  200. autobyteus/llm/api/openai_llm.py +3 -3
  201. autobyteus/llm/api/openai_responses_llm.py +324 -0
  202. autobyteus/llm/api/zhipu_llm.py +21 -2
  203. autobyteus/llm/autobyteus_provider.py +70 -60
  204. autobyteus/llm/base_llm.py +85 -81
  205. autobyteus/llm/converters/__init__.py +14 -0
  206. autobyteus/llm/converters/anthropic_tool_call_converter.py +37 -0
  207. autobyteus/llm/converters/gemini_tool_call_converter.py +57 -0
  208. autobyteus/llm/converters/mistral_tool_call_converter.py +37 -0
  209. autobyteus/llm/converters/openai_tool_call_converter.py +38 -0
  210. autobyteus/llm/extensions/base_extension.py +6 -12
  211. autobyteus/llm/extensions/token_usage_tracking_extension.py +45 -18
  212. autobyteus/llm/llm_factory.py +282 -204
  213. autobyteus/llm/lmstudio_provider.py +60 -49
  214. autobyteus/llm/models.py +35 -2
  215. autobyteus/llm/ollama_provider.py +60 -49
  216. autobyteus/llm/ollama_provider_resolver.py +0 -1
  217. autobyteus/llm/prompt_renderers/__init__.py +19 -0
  218. autobyteus/llm/prompt_renderers/anthropic_prompt_renderer.py +104 -0
  219. autobyteus/llm/prompt_renderers/autobyteus_prompt_renderer.py +19 -0
  220. autobyteus/llm/prompt_renderers/base_prompt_renderer.py +10 -0
  221. autobyteus/llm/prompt_renderers/gemini_prompt_renderer.py +63 -0
  222. autobyteus/llm/prompt_renderers/mistral_prompt_renderer.py +87 -0
  223. autobyteus/llm/prompt_renderers/ollama_prompt_renderer.py +51 -0
  224. autobyteus/llm/prompt_renderers/openai_chat_renderer.py +97 -0
  225. autobyteus/llm/prompt_renderers/openai_responses_renderer.py +101 -0
  226. autobyteus/llm/providers.py +1 -3
  227. autobyteus/llm/token_counter/claude_token_counter.py +56 -25
  228. autobyteus/llm/token_counter/mistral_token_counter.py +12 -8
  229. autobyteus/llm/token_counter/openai_token_counter.py +24 -5
  230. autobyteus/llm/token_counter/token_counter_factory.py +12 -5
  231. autobyteus/llm/utils/llm_config.py +6 -12
  232. autobyteus/llm/utils/media_payload_formatter.py +27 -20
  233. autobyteus/llm/utils/messages.py +55 -3
  234. autobyteus/llm/utils/response_types.py +3 -0
  235. autobyteus/llm/utils/tool_call_delta.py +31 -0
  236. autobyteus/memory/__init__.py +32 -0
  237. autobyteus/memory/active_transcript.py +69 -0
  238. autobyteus/memory/compaction/__init__.py +9 -0
  239. autobyteus/memory/compaction/compaction_result.py +8 -0
  240. autobyteus/memory/compaction/compactor.py +89 -0
  241. autobyteus/memory/compaction/summarizer.py +11 -0
  242. autobyteus/memory/compaction_snapshot_builder.py +84 -0
  243. autobyteus/memory/memory_manager.py +183 -0
  244. autobyteus/memory/models/__init__.py +14 -0
  245. autobyteus/memory/models/episodic_item.py +41 -0
  246. autobyteus/memory/models/memory_types.py +7 -0
  247. autobyteus/memory/models/raw_trace_item.py +79 -0
  248. autobyteus/memory/models/semantic_item.py +41 -0
  249. autobyteus/memory/models/tool_interaction.py +20 -0
  250. autobyteus/memory/policies/__init__.py +5 -0
  251. autobyteus/memory/policies/compaction_policy.py +16 -0
  252. autobyteus/memory/retrieval/__init__.py +7 -0
  253. autobyteus/memory/retrieval/memory_bundle.py +11 -0
  254. autobyteus/memory/retrieval/retriever.py +13 -0
  255. autobyteus/memory/store/__init__.py +7 -0
  256. autobyteus/memory/store/base_store.py +14 -0
  257. autobyteus/memory/store/file_store.py +98 -0
  258. autobyteus/memory/tool_interaction_builder.py +46 -0
  259. autobyteus/memory/turn_tracker.py +9 -0
  260. autobyteus/multimedia/audio/api/__init__.py +3 -2
  261. autobyteus/multimedia/audio/api/autobyteus_audio_client.py +19 -5
  262. autobyteus/multimedia/audio/api/gemini_audio_client.py +108 -16
  263. autobyteus/multimedia/audio/api/openai_audio_client.py +112 -0
  264. autobyteus/multimedia/audio/audio_client_factory.py +84 -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 +38 -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/__init__.py +43 -20
  277. autobyteus/task_management/{base_task_board.py → base_task_plan.py} +16 -13
  278. autobyteus/task_management/converters/__init__.py +2 -2
  279. autobyteus/task_management/converters/{task_board_converter.py → task_plan_converter.py} +13 -13
  280. autobyteus/task_management/events.py +7 -7
  281. autobyteus/task_management/{in_memory_task_board.py → in_memory_task_plan.py} +34 -22
  282. autobyteus/task_management/schemas/__init__.py +3 -0
  283. autobyteus/task_management/schemas/task_status_report.py +2 -2
  284. autobyteus/task_management/schemas/todo_definition.py +15 -0
  285. autobyteus/task_management/todo.py +29 -0
  286. autobyteus/task_management/todo_list.py +75 -0
  287. autobyteus/task_management/tools/__init__.py +24 -8
  288. autobyteus/task_management/tools/task_tools/__init__.py +19 -0
  289. autobyteus/task_management/tools/{assign_task_to.py → task_tools/assign_task_to.py} +18 -18
  290. autobyteus/task_management/tools/{publish_task.py → task_tools/create_task.py} +16 -18
  291. autobyteus/task_management/tools/{publish_tasks.py → task_tools/create_tasks.py} +19 -19
  292. autobyteus/task_management/tools/{get_my_tasks.py → task_tools/get_my_tasks.py} +15 -15
  293. autobyteus/task_management/tools/{get_task_board_status.py → task_tools/get_task_plan_status.py} +16 -16
  294. autobyteus/task_management/tools/{update_task_status.py → task_tools/update_task_status.py} +16 -16
  295. autobyteus/task_management/tools/todo_tools/__init__.py +18 -0
  296. autobyteus/task_management/tools/todo_tools/add_todo.py +78 -0
  297. autobyteus/task_management/tools/todo_tools/create_todo_list.py +79 -0
  298. autobyteus/task_management/tools/todo_tools/get_todo_list.py +55 -0
  299. autobyteus/task_management/tools/todo_tools/update_todo_status.py +85 -0
  300. autobyteus/tools/__init__.py +43 -52
  301. autobyteus/tools/base_tool.py +7 -0
  302. autobyteus/tools/file/__init__.py +9 -0
  303. autobyteus/tools/file/patch_file.py +149 -0
  304. autobyteus/tools/file/{file_reader.py → read_file.py} +38 -7
  305. autobyteus/tools/file/{file_writer.py → write_file.py} +7 -4
  306. autobyteus/tools/functional_tool.py +53 -14
  307. autobyteus/tools/mcp/__init__.py +2 -0
  308. autobyteus/tools/mcp/config_service.py +5 -1
  309. autobyteus/tools/mcp/server/__init__.py +2 -0
  310. autobyteus/tools/mcp/server/http_managed_mcp_server.py +1 -1
  311. autobyteus/tools/mcp/server/websocket_managed_mcp_server.py +141 -0
  312. autobyteus/tools/mcp/server_instance_manager.py +8 -1
  313. autobyteus/tools/mcp/tool.py +3 -3
  314. autobyteus/tools/mcp/tool_registrar.py +5 -2
  315. autobyteus/tools/mcp/types.py +61 -0
  316. autobyteus/tools/multimedia/__init__.py +2 -1
  317. autobyteus/tools/multimedia/audio_tools.py +72 -19
  318. autobyteus/tools/{download_media_tool.py → multimedia/download_media_tool.py} +21 -7
  319. autobyteus/tools/multimedia/image_tools.py +248 -64
  320. autobyteus/tools/multimedia/media_reader_tool.py +1 -1
  321. autobyteus/tools/operation_executor/journal_manager.py +107 -0
  322. autobyteus/tools/operation_executor/operation_event_buffer.py +57 -0
  323. autobyteus/tools/operation_executor/operation_event_producer.py +29 -0
  324. autobyteus/tools/operation_executor/operation_executor.py +58 -0
  325. autobyteus/tools/registry/tool_definition.py +108 -14
  326. autobyteus/tools/registry/tool_registry.py +29 -0
  327. autobyteus/tools/search/__init__.py +17 -0
  328. autobyteus/tools/search/base_strategy.py +35 -0
  329. autobyteus/tools/search/client.py +24 -0
  330. autobyteus/tools/search/factory.py +81 -0
  331. autobyteus/tools/search/google_cse_strategy.py +68 -0
  332. autobyteus/tools/search/providers.py +10 -0
  333. autobyteus/tools/search/serpapi_strategy.py +65 -0
  334. autobyteus/tools/search/serper_strategy.py +87 -0
  335. autobyteus/tools/search_tool.py +83 -0
  336. autobyteus/tools/skill/load_skill.py +50 -0
  337. autobyteus/tools/terminal/__init__.py +45 -0
  338. autobyteus/tools/terminal/ansi_utils.py +32 -0
  339. autobyteus/tools/terminal/background_process_manager.py +233 -0
  340. autobyteus/tools/terminal/output_buffer.py +105 -0
  341. autobyteus/tools/terminal/prompt_detector.py +63 -0
  342. autobyteus/tools/terminal/pty_session.py +241 -0
  343. autobyteus/tools/terminal/session_factory.py +20 -0
  344. autobyteus/tools/terminal/terminal_session_manager.py +226 -0
  345. autobyteus/tools/terminal/tools/__init__.py +13 -0
  346. autobyteus/tools/terminal/tools/get_process_output.py +81 -0
  347. autobyteus/tools/terminal/tools/run_bash.py +109 -0
  348. autobyteus/tools/terminal/tools/start_background_process.py +104 -0
  349. autobyteus/tools/terminal/tools/stop_background_process.py +67 -0
  350. autobyteus/tools/terminal/types.py +54 -0
  351. autobyteus/tools/terminal/wsl_tmux_session.py +221 -0
  352. autobyteus/tools/terminal/wsl_utils.py +156 -0
  353. autobyteus/tools/tool_meta.py +4 -24
  354. autobyteus/tools/transaction_management/backup_handler.py +48 -0
  355. autobyteus/tools/transaction_management/operation_lifecycle_manager.py +62 -0
  356. autobyteus/tools/usage/__init__.py +1 -2
  357. autobyteus/tools/usage/formatters/__init__.py +17 -1
  358. autobyteus/tools/usage/formatters/base_formatter.py +8 -0
  359. autobyteus/tools/usage/formatters/default_xml_schema_formatter.py +2 -2
  360. autobyteus/tools/usage/formatters/mistral_json_schema_formatter.py +18 -0
  361. autobyteus/tools/usage/formatters/patch_file_xml_example_formatter.py +64 -0
  362. autobyteus/tools/usage/formatters/patch_file_xml_schema_formatter.py +31 -0
  363. autobyteus/tools/usage/formatters/run_bash_xml_example_formatter.py +32 -0
  364. autobyteus/tools/usage/formatters/run_bash_xml_schema_formatter.py +36 -0
  365. autobyteus/tools/usage/formatters/write_file_xml_example_formatter.py +53 -0
  366. autobyteus/tools/usage/formatters/write_file_xml_schema_formatter.py +31 -0
  367. autobyteus/tools/usage/providers/tool_manifest_provider.py +10 -10
  368. autobyteus/tools/usage/registries/__init__.py +1 -3
  369. autobyteus/tools/usage/registries/tool_formatting_registry.py +115 -8
  370. autobyteus/tools/usage/tool_schema_provider.py +51 -0
  371. autobyteus/tools/web/__init__.py +4 -0
  372. autobyteus/tools/web/read_url_tool.py +80 -0
  373. autobyteus/utils/diff_utils.py +271 -0
  374. autobyteus/utils/download_utils.py +109 -0
  375. autobyteus/utils/file_utils.py +57 -2
  376. autobyteus/utils/gemini_helper.py +56 -0
  377. autobyteus/utils/gemini_model_mapping.py +71 -0
  378. autobyteus/utils/llm_output_formatter.py +75 -0
  379. autobyteus/utils/tool_call_format.py +36 -0
  380. autobyteus/workflow/agentic_workflow.py +3 -3
  381. autobyteus/workflow/bootstrap_steps/agent_tool_injection_step.py +2 -2
  382. autobyteus/workflow/bootstrap_steps/base_workflow_bootstrap_step.py +2 -2
  383. autobyteus/workflow/bootstrap_steps/coordinator_initialization_step.py +2 -2
  384. autobyteus/workflow/bootstrap_steps/coordinator_prompt_preparation_step.py +4 -11
  385. autobyteus/workflow/bootstrap_steps/workflow_bootstrapper.py +6 -6
  386. autobyteus/workflow/bootstrap_steps/workflow_runtime_queue_initialization_step.py +2 -2
  387. autobyteus/workflow/context/workflow_context.py +3 -3
  388. autobyteus/workflow/context/workflow_runtime_state.py +5 -5
  389. autobyteus/workflow/events/workflow_event_dispatcher.py +5 -5
  390. autobyteus/workflow/handlers/lifecycle_workflow_event_handler.py +3 -3
  391. autobyteus/workflow/handlers/process_user_message_event_handler.py +5 -5
  392. autobyteus/workflow/handlers/tool_approval_workflow_event_handler.py +2 -2
  393. autobyteus/workflow/runtime/workflow_runtime.py +8 -8
  394. autobyteus/workflow/runtime/workflow_worker.py +3 -3
  395. autobyteus/workflow/status/__init__.py +11 -0
  396. autobyteus/workflow/status/workflow_status.py +19 -0
  397. autobyteus/workflow/status/workflow_status_manager.py +48 -0
  398. autobyteus/workflow/streaming/__init__.py +2 -2
  399. autobyteus/workflow/streaming/workflow_event_notifier.py +7 -7
  400. autobyteus/workflow/streaming/workflow_stream_event_payloads.py +4 -4
  401. autobyteus/workflow/streaming/workflow_stream_events.py +3 -3
  402. autobyteus/workflow/utils/wait_for_idle.py +4 -4
  403. autobyteus-1.2.3.dist-info/METADATA +293 -0
  404. autobyteus-1.2.3.dist-info/RECORD +600 -0
  405. {autobyteus-1.2.0.dist-info → autobyteus-1.2.3.dist-info}/WHEEL +1 -1
  406. {autobyteus-1.2.0.dist-info → autobyteus-1.2.3.dist-info}/top_level.txt +0 -1
  407. autobyteus/agent/bootstrap_steps/agent_runtime_queue_initialization_step.py +0 -57
  408. autobyteus/agent/hooks/__init__.py +0 -16
  409. autobyteus/agent/hooks/base_phase_hook.py +0 -78
  410. autobyteus/agent/hooks/hook_definition.py +0 -36
  411. autobyteus/agent/hooks/hook_meta.py +0 -37
  412. autobyteus/agent/hooks/hook_registry.py +0 -106
  413. autobyteus/agent/llm_response_processor/provider_aware_tool_usage_processor.py +0 -103
  414. autobyteus/agent/phases/__init__.py +0 -18
  415. autobyteus/agent/phases/discover.py +0 -53
  416. autobyteus/agent/phases/manager.py +0 -265
  417. autobyteus/agent/phases/transition_decorator.py +0 -40
  418. autobyteus/agent/phases/transition_info.py +0 -33
  419. autobyteus/agent/remote_agent.py +0 -244
  420. autobyteus/agent/workspace/workspace_definition.py +0 -36
  421. autobyteus/agent/workspace/workspace_meta.py +0 -37
  422. autobyteus/agent/workspace/workspace_registry.py +0 -72
  423. autobyteus/agent_team/bootstrap_steps/agent_team_runtime_queue_initialization_step.py +0 -25
  424. autobyteus/agent_team/bootstrap_steps/coordinator_prompt_preparation_step.py +0 -85
  425. autobyteus/agent_team/phases/__init__.py +0 -11
  426. autobyteus/agent_team/phases/agent_team_operational_phase.py +0 -19
  427. autobyteus/agent_team/phases/agent_team_phase_manager.py +0 -48
  428. autobyteus/llm/api/bedrock_llm.py +0 -92
  429. autobyteus/llm/api/groq_llm.py +0 -94
  430. autobyteus/llm/api/nvidia_llm.py +0 -108
  431. autobyteus/llm/utils/token_pricing_config.py +0 -87
  432. autobyteus/person/examples/sample_persons.py +0 -14
  433. autobyteus/person/examples/sample_roles.py +0 -14
  434. autobyteus/person/person.py +0 -29
  435. autobyteus/person/role.py +0 -14
  436. autobyteus/rpc/__init__.py +0 -73
  437. autobyteus/rpc/client/__init__.py +0 -17
  438. autobyteus/rpc/client/abstract_client_connection.py +0 -124
  439. autobyteus/rpc/client/client_connection_manager.py +0 -153
  440. autobyteus/rpc/client/sse_client_connection.py +0 -306
  441. autobyteus/rpc/client/stdio_client_connection.py +0 -280
  442. autobyteus/rpc/config/__init__.py +0 -13
  443. autobyteus/rpc/config/agent_server_config.py +0 -153
  444. autobyteus/rpc/config/agent_server_registry.py +0 -152
  445. autobyteus/rpc/hosting.py +0 -244
  446. autobyteus/rpc/protocol.py +0 -244
  447. autobyteus/rpc/server/__init__.py +0 -20
  448. autobyteus/rpc/server/agent_server_endpoint.py +0 -181
  449. autobyteus/rpc/server/base_method_handler.py +0 -40
  450. autobyteus/rpc/server/method_handlers.py +0 -259
  451. autobyteus/rpc/server/sse_server_handler.py +0 -182
  452. autobyteus/rpc/server/stdio_server_handler.py +0 -151
  453. autobyteus/rpc/server_main.py +0 -198
  454. autobyteus/rpc/transport_type.py +0 -13
  455. autobyteus/tools/bash/__init__.py +0 -2
  456. autobyteus/tools/bash/bash_executor.py +0 -100
  457. autobyteus/tools/browser/__init__.py +0 -2
  458. autobyteus/tools/browser/session_aware/__init__.py +0 -0
  459. autobyteus/tools/browser/session_aware/browser_session_aware_navigate_to.py +0 -75
  460. autobyteus/tools/browser/session_aware/browser_session_aware_tool.py +0 -30
  461. autobyteus/tools/browser/session_aware/browser_session_aware_web_element_trigger.py +0 -154
  462. autobyteus/tools/browser/session_aware/browser_session_aware_webpage_reader.py +0 -89
  463. autobyteus/tools/browser/session_aware/browser_session_aware_webpage_screenshot_taker.py +0 -107
  464. autobyteus/tools/browser/session_aware/factory/__init__.py +0 -0
  465. autobyteus/tools/browser/session_aware/factory/browser_session_aware_web_element_trigger_factory.py +0 -14
  466. autobyteus/tools/browser/session_aware/factory/browser_session_aware_webpage_reader_factory.py +0 -26
  467. autobyteus/tools/browser/session_aware/factory/browser_session_aware_webpage_screenshot_taker_factory.py +0 -14
  468. autobyteus/tools/browser/session_aware/shared_browser_session.py +0 -11
  469. autobyteus/tools/browser/session_aware/shared_browser_session_manager.py +0 -25
  470. autobyteus/tools/browser/session_aware/web_element_action.py +0 -20
  471. autobyteus/tools/browser/standalone/__init__.py +0 -6
  472. autobyteus/tools/browser/standalone/factory/__init__.py +0 -0
  473. autobyteus/tools/browser/standalone/factory/webpage_reader_factory.py +0 -25
  474. autobyteus/tools/browser/standalone/factory/webpage_screenshot_taker_factory.py +0 -14
  475. autobyteus/tools/browser/standalone/navigate_to.py +0 -80
  476. autobyteus/tools/browser/standalone/web_page_pdf_generator.py +0 -97
  477. autobyteus/tools/browser/standalone/webpage_image_downloader.py +0 -165
  478. autobyteus/tools/browser/standalone/webpage_reader.py +0 -101
  479. autobyteus/tools/browser/standalone/webpage_screenshot_taker.py +0 -101
  480. autobyteus/tools/file/file_editor.py +0 -200
  481. autobyteus/tools/google_search.py +0 -149
  482. autobyteus/tools/timer.py +0 -171
  483. autobyteus/tools/usage/parsers/__init__.py +0 -22
  484. autobyteus/tools/usage/parsers/_json_extractor.py +0 -99
  485. autobyteus/tools/usage/parsers/_string_decoders.py +0 -18
  486. autobyteus/tools/usage/parsers/anthropic_xml_tool_usage_parser.py +0 -10
  487. autobyteus/tools/usage/parsers/base_parser.py +0 -41
  488. autobyteus/tools/usage/parsers/default_json_tool_usage_parser.py +0 -83
  489. autobyteus/tools/usage/parsers/default_xml_tool_usage_parser.py +0 -316
  490. autobyteus/tools/usage/parsers/exceptions.py +0 -13
  491. autobyteus/tools/usage/parsers/gemini_json_tool_usage_parser.py +0 -77
  492. autobyteus/tools/usage/parsers/openai_json_tool_usage_parser.py +0 -149
  493. autobyteus/tools/usage/parsers/provider_aware_tool_usage_parser.py +0 -59
  494. autobyteus/tools/usage/registries/tool_usage_parser_registry.py +0 -62
  495. autobyteus/workflow/phases/__init__.py +0 -11
  496. autobyteus/workflow/phases/workflow_operational_phase.py +0 -19
  497. autobyteus/workflow/phases/workflow_phase_manager.py +0 -48
  498. autobyteus-1.2.0.dist-info/METADATA +0 -205
  499. autobyteus-1.2.0.dist-info/RECORD +0 -496
  500. examples/__init__.py +0 -1
  501. examples/agent_team/__init__.py +0 -1
  502. examples/discover_phase_transitions.py +0 -104
  503. examples/run_browser_agent.py +0 -262
  504. examples/run_google_slides_agent.py +0 -287
  505. examples/run_mcp_browser_client.py +0 -174
  506. examples/run_mcp_google_slides_client.py +0 -270
  507. examples/run_mcp_list_tools.py +0 -189
  508. examples/run_poem_writer.py +0 -284
  509. examples/run_sqlite_agent.py +0 -295
  510. /autobyteus/{person → skills}/__init__.py +0 -0
  511. /autobyteus/{person/examples → tools/skill}/__init__.py +0 -0
  512. {autobyteus-1.2.0.dist-info → autobyteus-1.2.3.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,241 @@
1
+ """
2
+ PTY Session wrapper for stateful terminal sessions.
3
+
4
+ This module provides a pseudo-terminal (PTY) abstraction that spawns
5
+ a persistent bash shell, enabling stateful terminal operations where
6
+ directory changes, environment variables, and shell state persist
7
+ across commands.
8
+ """
9
+
10
+ import asyncio
11
+ import fcntl
12
+ import logging
13
+ import os
14
+ import pty
15
+ import select
16
+ import signal
17
+ import struct
18
+ import termios
19
+ from typing import Optional
20
+
21
+ logger = logging.getLogger(__name__)
22
+
23
+
24
+ class PtySession:
25
+ """PTY session implementation using the pty module.
26
+
27
+ Spawns a persistent bash shell that maintains state across commands.
28
+
29
+ For testing, create a MockPtySession with the same interface (duck typing).
30
+
31
+ Attributes:
32
+ session_id: Unique identifier for this session.
33
+ """
34
+
35
+ def __init__(self, session_id: str):
36
+ """Initialize a PTY session.
37
+
38
+ Args:
39
+ session_id: Unique identifier for this session.
40
+ """
41
+ self._session_id = session_id
42
+ self._master_fd: Optional[int] = None
43
+ self._pid: Optional[int] = None
44
+ self._closed = False
45
+ self._cwd: Optional[str] = None
46
+
47
+ @property
48
+ def session_id(self) -> str:
49
+ """Unique session identifier."""
50
+ return self._session_id
51
+
52
+ @property
53
+ def is_alive(self) -> bool:
54
+ """Check if the shell process is still running."""
55
+ if self._pid is None or self._closed:
56
+ return False
57
+ try:
58
+ # Check if process exists without waiting
59
+ pid, status = os.waitpid(self._pid, os.WNOHANG)
60
+ if pid == 0:
61
+ return True # Process still running
62
+ return False # Process exited
63
+ except ChildProcessError:
64
+ return False
65
+
66
+ async def start(self, cwd: str) -> None:
67
+ """Start a bash shell in a PTY.
68
+
69
+ Uses fork/exec to create a child process with a pseudo-terminal.
70
+
71
+ Args:
72
+ cwd: Working directory for the shell.
73
+
74
+ Raises:
75
+ RuntimeError: If session is already started.
76
+ OSError: If fork or PTY creation fails.
77
+ """
78
+ if self._master_fd is not None:
79
+ raise RuntimeError("Session already started")
80
+
81
+ self._cwd = cwd
82
+
83
+ # Create pseudo-terminal
84
+ master_fd, slave_fd = pty.openpty()
85
+
86
+ pid = os.fork()
87
+
88
+ if pid == 0:
89
+ # Child process
90
+ try:
91
+ os.close(master_fd)
92
+ os.setsid()
93
+
94
+ # Make slave the controlling terminal
95
+ fcntl.ioctl(slave_fd, termios.TIOCSCTTY, 0)
96
+
97
+ # Redirect stdin/stdout/stderr to slave
98
+ os.dup2(slave_fd, 0)
99
+ os.dup2(slave_fd, 1)
100
+ os.dup2(slave_fd, 2)
101
+
102
+ if slave_fd > 2:
103
+ os.close(slave_fd)
104
+
105
+ # Set environment variables for better UX
106
+ os.environ['TERM'] = 'xterm-256color'
107
+ # Simple prompt for easier detection
108
+ os.environ['PS1'] = r'\w $ '
109
+
110
+ # Change to working directory
111
+ os.chdir(cwd)
112
+
113
+ # Execute bash with minimal startup
114
+ os.execlp('bash', 'bash', '--norc', '--noprofile', '-i')
115
+ except Exception as e:
116
+ logger.error(f"Child process error: {e}")
117
+ os._exit(1)
118
+ else:
119
+ # Parent process
120
+ os.close(slave_fd)
121
+ self._master_fd = master_fd
122
+ self._pid = pid
123
+
124
+ # Set non-blocking mode
125
+ flags = fcntl.fcntl(master_fd, fcntl.F_GETFL)
126
+ fcntl.fcntl(master_fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
127
+
128
+ # Give bash a moment to start
129
+ await asyncio.sleep(0.1)
130
+
131
+ logger.info(f"Started PTY session {self._session_id} (pid={pid}) in {cwd}")
132
+
133
+ async def write(self, data: bytes) -> None:
134
+ """Write data to the PTY master.
135
+
136
+ Args:
137
+ data: Bytes to write to the terminal.
138
+
139
+ Raises:
140
+ RuntimeError: If session is closed or not started.
141
+ """
142
+ if self._closed:
143
+ raise RuntimeError("Session is closed")
144
+ if self._master_fd is None:
145
+ raise RuntimeError("Session not started")
146
+
147
+ try:
148
+ os.write(self._master_fd, data)
149
+ except OSError as e:
150
+ logger.error(f"Error writing to PTY: {e}")
151
+ raise
152
+
153
+ async def read(self, timeout: float = 0.1) -> Optional[bytes]:
154
+ """Read available data from the PTY.
155
+
156
+ Uses select for non-blocking read with timeout.
157
+
158
+ Args:
159
+ timeout: Maximum time to wait for data in seconds.
160
+
161
+ Returns:
162
+ Bytes read from PTY, or None if no data available.
163
+
164
+ Raises:
165
+ RuntimeError: If session not started.
166
+ """
167
+ if self._closed:
168
+ return None
169
+ if self._master_fd is None:
170
+ raise RuntimeError("Session not started")
171
+
172
+ try:
173
+ # Wait for data with timeout
174
+ readable, _, _ = select.select([self._master_fd], [], [], timeout)
175
+
176
+ if not readable:
177
+ return None
178
+
179
+ # Read available data
180
+ data = os.read(self._master_fd, 4096)
181
+ return data if data else None
182
+
183
+ except OSError as e:
184
+ if e.errno == 5: # EIO - terminal closed
185
+ return None
186
+ logger.error(f"Error reading from PTY: {e}")
187
+ raise
188
+
189
+ def resize(self, rows: int, cols: int) -> None:
190
+ """Resize the PTY terminal.
191
+
192
+ Args:
193
+ rows: Number of rows.
194
+ cols: Number of columns.
195
+ """
196
+ if self._master_fd is None:
197
+ raise RuntimeError("Session not started")
198
+ if self._closed:
199
+ return
200
+
201
+ try:
202
+ winsize = struct.pack('HHHH', rows, cols, 0, 0)
203
+ fcntl.ioctl(self._master_fd, termios.TIOCSWINSZ, winsize)
204
+ logger.debug(f"Resized PTY {self._session_id} to {rows}x{cols}")
205
+ except OSError as e:
206
+ logger.error(f"Error resizing PTY: {e}")
207
+
208
+ async def close(self) -> None:
209
+ """Close the PTY and terminate the shell.
210
+
211
+ Sends SIGTERM first, then SIGKILL if necessary.
212
+ """
213
+ if self._closed:
214
+ return
215
+
216
+ self._closed = True
217
+
218
+ if self._master_fd is not None:
219
+ try:
220
+ os.close(self._master_fd)
221
+ except OSError:
222
+ pass
223
+ self._master_fd = None
224
+
225
+ if self._pid is not None:
226
+ try:
227
+ # Try graceful termination first
228
+ os.kill(self._pid, signal.SIGTERM)
229
+ # Wait briefly
230
+ await asyncio.sleep(0.1)
231
+ # Force kill if still running
232
+ try:
233
+ os.kill(self._pid, signal.SIGKILL)
234
+ except ProcessLookupError:
235
+ pass # Already dead
236
+ os.waitpid(self._pid, 0)
237
+ except (ProcessLookupError, ChildProcessError):
238
+ pass
239
+ self._pid = None
240
+
241
+ logger.info(f"Closed PTY session {self._session_id}")
@@ -0,0 +1,20 @@
1
+ """
2
+ Session factory selection for terminal backends.
3
+ """
4
+
5
+ import os
6
+
7
+
8
+ def _is_windows() -> bool:
9
+ """Return True if running on Windows."""
10
+ return os.name == "nt"
11
+
12
+
13
+ def get_default_session_factory():
14
+ """Return the default PTY session class for the current platform."""
15
+ if _is_windows():
16
+ from autobyteus.tools.terminal.wsl_tmux_session import WslTmuxSession
17
+ return WslTmuxSession
18
+
19
+ from autobyteus.tools.terminal.pty_session import PtySession
20
+ return PtySession
@@ -0,0 +1,226 @@
1
+ """
2
+ Terminal Session Manager for executing commands in a stateful PTY.
3
+
4
+ Provides high-level command execution with prompt detection and
5
+ timeout handling.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import asyncio
11
+ import logging
12
+ import uuid
13
+ from typing import Callable, Optional
14
+
15
+ from autobyteus.tools.terminal.output_buffer import OutputBuffer
16
+ from autobyteus.tools.terminal.prompt_detector import PromptDetector
17
+ from autobyteus.tools.terminal.session_factory import get_default_session_factory
18
+ from autobyteus.tools.terminal.types import TerminalResult
19
+ from autobyteus.tools.terminal.ansi_utils import strip_ansi_codes
20
+
21
+ logger = logging.getLogger(__name__)
22
+
23
+
24
+ class TerminalSessionManager:
25
+ """Manages the main stateful terminal session for an agent.
26
+
27
+ Provides command execution with automatic prompt detection and
28
+ timeout handling. The underlying PTY maintains state between
29
+ commands (cd, environment variables, etc).
30
+
31
+ Attributes:
32
+ current_session: The active PTY session if started.
33
+ """
34
+
35
+ def __init__(
36
+ self,
37
+ session_factory: Callable[[str], object] = None,
38
+ prompt_detector: PromptDetector = None
39
+ ):
40
+ """Initialize the terminal session manager.
41
+
42
+ Args:
43
+ session_factory: Factory function to create PtySession instances.
44
+ Defaults to PtySession constructor.
45
+ prompt_detector: PromptDetector instance for command completion.
46
+ Defaults to standard PromptDetector.
47
+ """
48
+ self._session_factory = session_factory or get_default_session_factory()
49
+ self._prompt_detector = prompt_detector or PromptDetector()
50
+ self._session: Optional[object] = None
51
+ self._output_buffer = OutputBuffer()
52
+ self._cwd: Optional[str] = None
53
+ self._started = False
54
+
55
+ @property
56
+ def current_session(self) -> Optional[object]:
57
+ """The active PTY session if started."""
58
+ return self._session
59
+
60
+ @property
61
+ def is_started(self) -> bool:
62
+ """True if session has been started."""
63
+ return self._started and self._session is not None
64
+
65
+ async def ensure_started(self, cwd: str) -> None:
66
+ """Ensure the session is started.
67
+
68
+ Creates a new session if not already started.
69
+
70
+ Args:
71
+ cwd: Working directory for the shell.
72
+ """
73
+ if self._session is not None and self._session.is_alive:
74
+ return
75
+
76
+ # Clean up dead session if any
77
+ if self._session is not None:
78
+ await self._session.close()
79
+
80
+ session_id = f"term-{uuid.uuid4().hex[:8]}"
81
+ self._session = self._session_factory(session_id)
82
+ await self._session.start(cwd)
83
+ self._cwd = cwd
84
+ self._started = True
85
+
86
+ # Drain initial prompt output
87
+ await self._drain_output(timeout=0.5)
88
+ self._output_buffer.clear()
89
+
90
+ logger.info(f"Terminal session started in {cwd}")
91
+
92
+ async def execute_command(
93
+ self,
94
+ command: str,
95
+ timeout_seconds: int = 30
96
+ ) -> TerminalResult:
97
+ """Execute a command and wait for completion.
98
+
99
+ Writes the command to the PTY and waits for the prompt to
100
+ return, indicating command completion.
101
+
102
+ Args:
103
+ command: The bash command to execute.
104
+ timeout_seconds: Maximum time to wait for completion.
105
+
106
+ Returns:
107
+ TerminalResult with captured output.
108
+
109
+ Raises:
110
+ RuntimeError: If session is not started.
111
+ """
112
+ if self._session is None:
113
+ raise RuntimeError("Session not started. Call ensure_started first.")
114
+
115
+ # Clear buffer for this command
116
+ self._output_buffer.clear()
117
+
118
+ # Ensure command ends with newline
119
+ if not command.endswith('\n'):
120
+ command += '\n'
121
+
122
+ # Write command
123
+ await self._session.write(command.encode('utf-8'))
124
+
125
+ # Wait for prompt with timeout
126
+ timed_out = False
127
+ start_time = asyncio.get_event_loop().time()
128
+
129
+ while True:
130
+ elapsed = asyncio.get_event_loop().time() - start_time
131
+ if elapsed >= timeout_seconds:
132
+ timed_out = True
133
+ logger.warning(f"Command timed out after {timeout_seconds}s: {command.strip()}")
134
+ break
135
+
136
+ # Read available output
137
+ try:
138
+ data = await self._session.read(timeout=0.1)
139
+ if data:
140
+ self._output_buffer.append(data)
141
+
142
+ # Check if prompt returned
143
+ current_output = self._output_buffer.get_all()
144
+ if self._prompt_detector.check(current_output):
145
+ break
146
+ except Exception as e:
147
+ logger.error(f"Error reading from PTY: {e}")
148
+ break
149
+
150
+ # Get captured output and strip ANSI escape codes
151
+ output = self._output_buffer.get_all()
152
+ clean_output = strip_ansi_codes(output)
153
+
154
+ # Try to extract exit code if not timed out
155
+ exit_code = None
156
+ if not timed_out:
157
+ exit_code = await self._get_exit_code()
158
+
159
+ return TerminalResult(
160
+ stdout=clean_output,
161
+ stderr="", # PTY mixes stdout/stderr
162
+ exit_code=exit_code,
163
+ timed_out=timed_out
164
+ )
165
+
166
+ async def _get_exit_code(self) -> Optional[int]:
167
+ """Try to get the exit code of the last command.
168
+
169
+ Returns:
170
+ Exit code if successfully retrieved, None otherwise.
171
+ """
172
+ try:
173
+ # Clear buffer
174
+ self._output_buffer.clear()
175
+
176
+ # Echo the exit code
177
+ await self._session.write(b"echo $?\n")
178
+
179
+ # Wait for output
180
+ await asyncio.sleep(0.2)
181
+ await self._drain_output(timeout=0.3)
182
+
183
+ output = self._output_buffer.get_all()
184
+ output = strip_ansi_codes(output)
185
+
186
+ # Parse the exit code from output
187
+ lines = output.strip().split('\n')
188
+ for line in lines:
189
+ line = line.strip()
190
+ if line.isdigit():
191
+ return int(line)
192
+
193
+ return None
194
+ except Exception as e:
195
+ logger.debug(f"Failed to get exit code: {e}")
196
+ return None
197
+
198
+ async def _drain_output(self, timeout: float = 0.5) -> None:
199
+ """Read and buffer all available output.
200
+
201
+ Args:
202
+ timeout: Maximum time to wait for more output.
203
+ """
204
+ if self._session is None:
205
+ return
206
+
207
+ start = asyncio.get_event_loop().time()
208
+ while asyncio.get_event_loop().time() - start < timeout:
209
+ try:
210
+ data = await self._session.read(timeout=0.05)
211
+ if data:
212
+ self._output_buffer.append(data)
213
+ else:
214
+ # No more data immediately available
215
+ await asyncio.sleep(0.05)
216
+ except Exception:
217
+ break
218
+
219
+ async def close(self) -> None:
220
+ """Close the terminal session."""
221
+ if self._session is not None:
222
+ await self._session.close()
223
+ self._session = None
224
+ self._started = False
225
+ self._output_buffer.clear()
226
+ logger.info("Terminal session closed")
@@ -0,0 +1,13 @@
1
+ """Terminal tools package - LLM-facing tool functions."""
2
+
3
+ from autobyteus.tools.terminal.tools.run_bash import run_bash
4
+ from autobyteus.tools.terminal.tools.start_background_process import start_background_process
5
+ from autobyteus.tools.terminal.tools.get_process_output import get_process_output
6
+ from autobyteus.tools.terminal.tools.stop_background_process import stop_background_process
7
+
8
+ __all__ = [
9
+ "run_bash",
10
+ "start_background_process",
11
+ "get_process_output",
12
+ "stop_background_process",
13
+ ]
@@ -0,0 +1,81 @@
1
+ """
2
+ get_process_output tool - Read output from background processes.
3
+
4
+ Returns recent output from a background process started with
5
+ start_background_process.
6
+ """
7
+
8
+ import logging
9
+ from typing import TYPE_CHECKING, Optional
10
+
11
+ from autobyteus.tools import tool
12
+ from autobyteus.tools.tool_category import ToolCategory
13
+
14
+ if TYPE_CHECKING:
15
+ from autobyteus.agent.context import AgentContext
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+
20
+ def _get_background_manager(context: Optional['AgentContext']):
21
+ """Get the background process manager for this agent."""
22
+ from autobyteus.tools.terminal.background_process_manager import BackgroundProcessManager
23
+
24
+ if context is None:
25
+ if not hasattr(_get_background_manager, '_default_manager'):
26
+ _get_background_manager._default_manager = BackgroundProcessManager()
27
+ return _get_background_manager._default_manager
28
+
29
+ if not hasattr(context, '_background_process_manager'):
30
+ context._background_process_manager = BackgroundProcessManager()
31
+
32
+ return context._background_process_manager
33
+
34
+
35
+ @tool(name="get_process_output", category=ToolCategory.SYSTEM)
36
+ async def get_process_output(
37
+ context: Optional['AgentContext'],
38
+ process_id: str,
39
+ lines: int = 100
40
+ ) -> dict:
41
+ """
42
+ Get recent output from a background process.
43
+
44
+ Use this to check what a background process (started with
45
+ start_background_process) is outputting. This is useful to:
46
+ - Verify a server started successfully
47
+ - Check for errors in the output
48
+ - Monitor progress of a long-running task
49
+
50
+ Args:
51
+ process_id: ID returned by start_background_process.
52
+ lines: Number of recent lines to return (default 100).
53
+
54
+ Returns:
55
+ dict with:
56
+ - output: Recent output lines from the process
57
+ - is_running: True if process is still running
58
+ - process_id: The process identifier
59
+
60
+ Examples:
61
+ - After starting "yarn dev", check output to verify server is ready
62
+ - Check for compilation errors in build output
63
+ - Monitor test runner output
64
+ """
65
+ manager = _get_background_manager(context)
66
+
67
+ try:
68
+ result = manager.get_output(process_id, lines)
69
+ return {
70
+ "output": result.output,
71
+ "is_running": result.is_running,
72
+ "process_id": result.process_id
73
+ }
74
+ except KeyError:
75
+ logger.warning(f"Process not found: {process_id}")
76
+ return {
77
+ "output": "",
78
+ "is_running": False,
79
+ "process_id": process_id,
80
+ "error": f"Process '{process_id}' not found. It may have already stopped or never existed."
81
+ }
@@ -0,0 +1,109 @@
1
+ """
2
+ run_bash tool - Execute commands in a stateful terminal.
3
+
4
+ This tool replaces the stateless bash_executor with a PTY-based
5
+ implementation that maintains shell state (cd, environment variables).
6
+ """
7
+
8
+ import logging
9
+ from typing import TYPE_CHECKING, Optional
10
+
11
+ from autobyteus.tools import tool
12
+ from autobyteus.tools.tool_category import ToolCategory
13
+ from autobyteus.tools.terminal.types import TerminalResult
14
+
15
+ if TYPE_CHECKING:
16
+ from autobyteus.agent.context import AgentContext
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ def _get_terminal_manager(context: Optional['AgentContext']):
22
+ """Get or create the terminal session manager for this agent.
23
+
24
+ Args:
25
+ context: The agent context.
26
+
27
+ Returns:
28
+ TerminalSessionManager instance.
29
+ """
30
+ from autobyteus.tools.terminal.terminal_session_manager import TerminalSessionManager
31
+
32
+ if context is None:
33
+ # Fallback for non-agent use
34
+ if not hasattr(_get_terminal_manager, '_default_manager'):
35
+ _get_terminal_manager._default_manager = TerminalSessionManager()
36
+ return _get_terminal_manager._default_manager
37
+
38
+ # Store manager in context for per-agent isolation
39
+ if not hasattr(context, '_terminal_session_manager'):
40
+ context._terminal_session_manager = TerminalSessionManager()
41
+
42
+ return context._terminal_session_manager
43
+
44
+
45
+ def _get_cwd(context: Optional['AgentContext']) -> str:
46
+ """Get the working directory for the terminal.
47
+
48
+ Args:
49
+ context: The agent context.
50
+
51
+ Returns:
52
+ Working directory path.
53
+ """
54
+ import tempfile
55
+
56
+ if context and hasattr(context, 'workspace') and context.workspace:
57
+ try:
58
+ base_path = context.workspace.get_base_path()
59
+ if base_path and isinstance(base_path, str):
60
+ return base_path
61
+ except Exception:
62
+ pass
63
+
64
+ return tempfile.gettempdir()
65
+
66
+
67
+ @tool(name="run_bash", category=ToolCategory.SYSTEM)
68
+ async def run_bash(
69
+ context: Optional['AgentContext'],
70
+ command: str,
71
+ timeout_seconds: int = 30
72
+ ) -> TerminalResult:
73
+ """
74
+ Execute a command in the terminal and wait for completion.
75
+
76
+ This tool is STATELESS. Each command runs in a fresh shell session.
77
+ Directory changes (cd) and environment variables (export) DO NOT persist
78
+ between calls. You must chain commands if state dependence is needed.
79
+
80
+ Args:
81
+ command: The bash command to execute.
82
+ timeout_seconds: Maximum time to wait for completion (default 30s).
83
+ Command is killed if timeout is exceeded.
84
+
85
+ Returns:
86
+ TerminalResult with:
87
+ - stdout: Output from the command
88
+ - stderr: Error output (may be mixed with stdout in PTY)
89
+ - exit_code: Exit code if available
90
+ - timed_out: True if command exceeded timeout
91
+
92
+ Examples:
93
+ - run_bash("ls -la")
94
+ - run_bash("cd src && npm install", timeout_seconds=120) # Correct way to run in subdir
95
+ - run_bash("cd src; ls") # Correct way to list subdir
96
+ """
97
+ manager = _get_terminal_manager(context)
98
+ cwd = _get_cwd(context)
99
+
100
+ # Ensure session is started
101
+ await manager.ensure_started(cwd)
102
+
103
+ logger.debug(f"Executing terminal command: {command}")
104
+ result = await manager.execute_command(command, timeout_seconds)
105
+
106
+ if result.timed_out:
107
+ logger.warning(f"Command timed out: {command}")
108
+
109
+ return result