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
@@ -1,306 +0,0 @@
1
- # file: autobyteus/autobyteus/rpc/client/sse_client_connection.py
2
- import asyncio
3
- import logging
4
- import json
5
- from typing import Optional, AsyncIterator, Dict, Any # Added Dict, Any
6
-
7
- import aiohttp
8
- from aiohttp_sse_client.client import EventSource # type: ignore
9
-
10
- from autobyteus.rpc.protocol import ProtocolMessage, MessageType, ErrorCode, EventType, RequestType, ResponseType # Added RequestType, ResponseType
11
- from .abstract_client_connection import AbstractClientConnection
12
- from autobyteus.rpc.config import AgentServerConfig, TransportType # Added TransportType from config
13
-
14
- logger = logging.getLogger(__name__)
15
-
16
- DEFAULT_SSE_TIMEOUT = 30.0 # seconds for an HTTP request response
17
- DEFAULT_SSE_RECONNECTION_TIME = 5 # seconds
18
- DEFAULT_STREAM_DOWNLOAD_TIMEOUT = 300.0 # 5 minutes for stream download requests
19
-
20
- class SseClientConnection(AbstractClientConnection):
21
- """
22
- Client connection implementation for SSE-based Agent Servers.
23
- Uses aiohttp for HTTP requests and aiohttp-sse-client for consuming SSE event streams.
24
- Also supports direct HTTP stream downloads.
25
- """
26
-
27
- def __init__(self, server_config: AgentServerConfig):
28
- """
29
- Initializes the SseClientConnection.
30
-
31
- Args:
32
- server_config: The configuration for the SSE server.
33
-
34
- Raises:
35
- ValueError: If server_config is not for SSE or base URL is missing.
36
- """
37
- if server_config.transport_type != TransportType.SSE: # Use Enum member
38
- raise ValueError("SseClientConnection requires an AgentServerConfig with transport_type 'sse'.")
39
- if not server_config.sse_base_url:
40
- raise ValueError("AgentServerConfig for sse transport must have an sse_base_url.")
41
-
42
- super().__init__(server_id=server_config.server_id)
43
- self.server_config: AgentServerConfig = server_config
44
- self._session: Optional[aiohttp.ClientSession] = None
45
- self._event_source: Optional[EventSource] = None
46
-
47
- async def connect(self) -> None:
48
- """
49
- Establishes the aiohttp ClientSession. For SSE, actual connection
50
- to event stream happens when events() is iterated.
51
- """
52
- async with self._connection_lock:
53
- if self._is_connected and self._session and not self._session.closed:
54
- logger.debug(f"SseClientConnection to '{self.server_id}' session already active.")
55
- return
56
-
57
- try:
58
- # Create a new session if it doesn't exist or is closed
59
- if not self._session or self._session.closed:
60
- self._session = aiohttp.ClientSession()
61
- logger.info(f"SseClientConnection to '{self.server_id}': new aiohttp.ClientSession created.")
62
-
63
- self._is_connected = True # Mark as connected once session is ready
64
- logger.info(f"SseClientConnection to '{self.server_id}' connected (session ready).")
65
- except Exception as e:
66
- logger.error(f"Failed to create/ensure aiohttp.ClientSession for '{self.server_id}': {e}", exc_info=True)
67
- self._is_connected = False
68
- if self._session and not self._session.closed:
69
- await self._session.close()
70
- self._session = None
71
- raise ConnectionError(f"Failed to initialize HTTP session for SSE server '{self.server_id}': {e}") from e
72
-
73
- async def close(self) -> None:
74
- """Closes the aiohttp ClientSession and any active EventSource."""
75
- async with self._connection_lock:
76
- if not self._is_connected and not self._session: # Check both state and session object
77
- logger.debug(f"SseClientConnection to '{self.server_id}' already closed or never connected.")
78
- return
79
-
80
- self._is_connected = False
81
-
82
- if self._event_source:
83
- try:
84
- await self._event_source.close()
85
- logger.debug(f"EventSource for '{self.server_id}' closed.")
86
- except Exception as e:
87
- logger.error(f"Error closing EventSource for '{self.server_id}': {e}", exc_info=True)
88
- self._event_source = None
89
-
90
- if self._session and not self._session.closed:
91
- try:
92
- await self._session.close()
93
- logger.debug(f"aiohttp.ClientSession for '{self.server_id}' closed.")
94
- except Exception as e:
95
- logger.error(f"Error closing aiohttp.ClientSession for '{self.server_id}': {e}", exc_info=True)
96
- self._session = None # Ensure session object is cleared
97
-
98
- logger.info(f"SseClientConnection to '{self.server_id}' closed.")
99
-
100
- async def send_request(self, request_message: ProtocolMessage) -> ProtocolMessage:
101
- """Sends a request via HTTP POST and awaits a JSON response."""
102
- if not self._is_connected or not self._session or self._session.closed:
103
- logger.info(f"SseClientConnection '{self.server_id}' not connected or session closed/missing. Attempting to connect before send_request.")
104
- await self.connect()
105
- if not self._is_connected or not self._session or self._session.closed: # Check again after connect attempt
106
- raise ConnectionError(f"Failed to connect to SSE server '{self.server_id}' for send_request (connection attempt failed).")
107
-
108
- if request_message.type != MessageType.REQUEST:
109
- raise ValueError("ProtocolMessage must be of type REQUEST to be sent via send_request.")
110
- if not request_message.id:
111
- raise ValueError("Request ProtocolMessage must have an ID.")
112
-
113
- request_url = self.server_config.get_sse_full_request_url()
114
- if not request_url:
115
- raise ValueError("SSE request URL is not configured.")
116
-
117
- logger.debug(f"SseClient '{self.server_id}' sending request to {request_url}: {request_message.to_json_str()}")
118
-
119
- try:
120
- async with self._session.post(
121
- request_url,
122
- json=request_message.model_dump(exclude_none=True),
123
- timeout=DEFAULT_SSE_TIMEOUT
124
- ) as response:
125
- response_text = await response.text()
126
- if response.status >= 200 and response.status < 300:
127
- try:
128
- return ProtocolMessage.from_json_str(response_text)
129
- except (json.JSONDecodeError, ValueError) as e:
130
- logger.error(f"Error decoding JSON response from '{request_url}': {e}. Response text: {response_text[:200]}")
131
- return ProtocolMessage.create_error_response(
132
- id=request_message.id,
133
- code=ErrorCode.PARSE_ERROR,
134
- message=f"Failed to parse JSON response from server: {e}"
135
- )
136
- else:
137
- logger.error(f"HTTP error from '{request_url}': {response.status} {response.reason}. Response: {response_text[:200]}")
138
- return ProtocolMessage.create_error_response(
139
- id=request_message.id,
140
- code=ErrorCode.INTERNAL_ERROR,
141
- message=f"Server returned HTTP error {response.status}: {response.reason}. Body: {response_text[:200]}"
142
- )
143
- except aiohttp.ClientConnectorError as e:
144
- logger.error(f"Connection error for '{request_url}': {e}", exc_info=True)
145
- await self.close() # Connection is likely broken, perform full close
146
- raise ConnectionError(f"Could not connect to SSE server at '{request_url}': {e}") from e
147
- except asyncio.TimeoutError:
148
- logger.warning(f"Timeout sending request to '{request_url}' for ID '{request_message.id}'.")
149
- # Don't necessarily close connection on timeout, server might be slow.
150
- return ProtocolMessage.create_error_response(
151
- id=request_message.id,
152
- code=ErrorCode.SERVER_ERROR_TIMEOUT,
153
- message=f"Timeout waiting for response from SSE server for request ID '{request_message.id}'."
154
- )
155
- except Exception as e:
156
- logger.error(f"Unexpected error sending request to '{request_url}': {e}", exc_info=True)
157
- if isinstance(e, (aiohttp.ClientError)):
158
- await self.close() # If it's a client lib error, connection might be compromised
159
- return ProtocolMessage.create_error_response(
160
- id=request_message.id,
161
- code=ErrorCode.INTERNAL_ERROR,
162
- message=f"Client-side error sending request: {e}"
163
- )
164
-
165
- async def events(self) -> AsyncIterator[ProtocolMessage]:
166
- """Connects to the SSE event stream and yields ProtocolMessages."""
167
- if not self._is_connected or not self._session or self._session.closed:
168
- logger.info(f"SseClientConnection '{self.server_id}' session not found or closed, attempting to connect before streaming events.")
169
- await self.connect()
170
- if not self._is_connected or not self._session or self._session.closed: # Check again
171
- raise ConnectionError(f"Not connected to SSE server '{self.server_id}' for event streaming (connection attempt failed).")
172
-
173
- # Construct event URL. Note: SseServerHandler expects /events/{agent_id_on_server}
174
- # The client config's server_id typically maps to an agent_id_on_server or is the agent_id_on_server.
175
- # For multi-agent servers, the client needs to know which agent_id_on_server to subscribe to.
176
- # This implies server_config.server_id is the agent_id_on_server for SSE event subscriptions.
177
- base_events_url = self.server_config.get_sse_full_events_url()
178
- if not base_events_url: # This is base path like /events
179
- raise ValueError("SSE events base URL path is not configured.")
180
-
181
- # Assuming self.server_id (from config) is the key for the agent on the server.
182
- events_url = f"{base_events_url.rstrip('/')}/{self.server_id}"
183
- logger.info(f"SseClient '{self.server_id}' connecting to event stream at {events_url}")
184
-
185
- if self._event_source: # Close existing if any
186
- await self._event_source.close()
187
- self._event_source = None
188
-
189
- try:
190
- self._event_source = EventSource(
191
- events_url,
192
- session=self._session, # Use existing session
193
- reconnection_time=DEFAULT_SSE_RECONNECTION_TIME,
194
- )
195
- await self._event_source.connect()
196
-
197
- async for sse_event in self._event_source:
198
- try:
199
- logger.debug(f"SseClient '{self.server_id}' received SSE event data: {sse_event.data[:200]}")
200
- msg = ProtocolMessage.from_json_str(sse_event.data)
201
- if msg.type == MessageType.EVENT:
202
- yield msg
203
- else:
204
- logger.warning(f"Received non-EVENT ProtocolMessage via SSE stream: {msg.type}. Ignoring.")
205
- except json.JSONDecodeError as e:
206
- logger.error(f"Error decoding JSON from SSE event data: {e}. Data: {sse_event.data[:200]}")
207
- except ValueError as e:
208
- logger.error(f"Error validating ProtocolMessage from SSE event data: {e}. Data: {sse_event.data[:200]}")
209
- except Exception as e:
210
- logger.error(f"Error processing SSE event: {e}", exc_info=True)
211
-
212
- except ConnectionRefusedError as e:
213
- logger.error(f"SSE EventStream for '{self.server_id}' connection refused at {events_url}: {e}")
214
- await self.close()
215
- raise ConnectionError(f"SSE EventStream connection refused: {e}") from e
216
- except aiohttp.ClientError as e:
217
- logger.error(f"SSE EventStream client error for '{self.server_id}' at {events_url}: {e}", exc_info=True)
218
- await self.close()
219
- raise ConnectionError(f"SSE EventStream client error: {e}") from e
220
- except asyncio.CancelledError:
221
- logger.info(f"SSE event stream for '{self.server_id}' cancelled.")
222
- if self._event_source: await self._event_source.close()
223
- raise
224
- except Exception as e:
225
- logger.error(f"Unexpected error in SSE event stream for '{self.server_id}': {e}", exc_info=True)
226
- if self._event_source: await self._event_source.close()
227
- await self.close()
228
- raise ConnectionError(f"Unexpected error in SSE event stream: {e}") from e
229
- finally:
230
- logger.info(f"SseClient '{self.server_id}' event stream iteration finished.")
231
- if self._event_source:
232
- await self._event_source.close()
233
- self._event_source = None
234
-
235
-
236
- async def request_and_download_stream(
237
- self,
238
- stream_request_params: Dict[str, Any],
239
- target_agent_id: str # This is the agent_id_on_server key
240
- ) -> AsyncIterator[bytes]:
241
- """
242
- Requests a stream download via RPC and then downloads the stream via HTTP GET.
243
- """
244
- if not self._is_connected or not self._session or self._session.closed:
245
- logger.info(f"SseClientConnection '{self.server_id}' not connected or session closed/missing. Attempting to connect before stream download.")
246
- await self.connect()
247
- if not self._is_connected or not self._session or self._session.closed:
248
- raise ConnectionError(f"Failed to connect to SSE server '{self.server_id}' for stream download (connection attempt failed).")
249
-
250
- # Step 1: RPC call to initiate stream download
251
- # The target_agent_id for the stream must be included in the params for the RPC call.
252
- rpc_params = {**stream_request_params, "target_agent_id": target_agent_id}
253
- initiate_request_msg = ProtocolMessage.create_request(
254
- method=RequestType.REQUEST_STREAM_DOWNLOAD,
255
- params=rpc_params
256
- )
257
-
258
- logger.debug(f"SseClient '{self.server_id}' sending stream download initiation request for target_agent_id '{target_agent_id}': {initiate_request_msg.to_json_str()}")
259
-
260
- initiate_response_msg = await self.send_request(initiate_request_msg)
261
-
262
- if initiate_response_msg.type == MessageType.ERROR or not initiate_response_msg.result:
263
- err_details = initiate_response_msg.error.message if initiate_response_msg.error else "Unknown error"
264
- logger.error(f"Failed to initiate stream download for target_agent_id '{target_agent_id}'. Server error: {err_details}")
265
- raise ValueError(f"Server error initiating stream download: {err_details}")
266
-
267
- if initiate_response_msg.response_type != ResponseType.STREAM_DOWNLOAD_READY:
268
- logger.error(f"Unexpected response type from stream download initiation: {initiate_response_msg.response_type}")
269
- raise ValueError(f"Unexpected response type: {initiate_response_msg.response_type}")
270
-
271
- download_url = initiate_response_msg.result.get("download_url")
272
- if not download_url:
273
- logger.error(f"No 'download_url' in STREAM_DOWNLOAD_READY response. Result: {initiate_response_msg.result}")
274
- raise ValueError("Server response did not include a download_url for the stream.")
275
-
276
- stream_metadata = initiate_response_msg.result.get("metadata", {})
277
- logger.info(f"SseClient '{self.server_id}' received download URL: {download_url}. Metadata: {stream_metadata}")
278
-
279
- # Step 2: HTTP GET request to the download_url
280
- try:
281
- logger.debug(f"SseClient '{self.server_id}' starting GET request to stream from {download_url}")
282
- async with self._session.get(download_url, timeout=DEFAULT_STREAM_DOWNLOAD_TIMEOUT) as response:
283
- response.raise_for_status() # Raise an exception for HTTP error codes (4xx or 5xx)
284
-
285
- # Stream the content
286
- async for chunk in response.content.iter_any(): # iter_any() or iter_chunked(chunk_size)
287
- yield chunk
288
- logger.info(f"SseClient '{self.server_id}' finished streaming from {download_url}")
289
-
290
- except aiohttp.ClientResponseError as e:
291
- logger.error(f"HTTP error during stream download from '{download_url}': {e.status} {e.message}", exc_info=True)
292
- # Connection might still be usable for other RPCs, don't necessarily close.
293
- raise ConnectionError(f"HTTP error downloading stream: {e.status} {e.message}") from e
294
- except aiohttp.ClientConnectorError as e:
295
- logger.error(f"Connection error during stream download from '{download_url}': {e}", exc_info=True)
296
- await self.close() # Connection likely broken
297
- raise ConnectionError(f"Could not connect to download stream at '{download_url}': {e}") from e
298
- except asyncio.TimeoutError:
299
- logger.warning(f"Timeout downloading stream from '{download_url}'.")
300
- # Don't close connection, server might be slow or stream very long with no data.
301
- raise TimeoutError(f"Timeout downloading stream from '{download_url}'.")
302
- except Exception as e:
303
- logger.error(f"Unexpected error downloading stream from '{download_url}': {e}", exc_info=True)
304
- if isinstance(e, (aiohttp.ClientError)):
305
- await self.close() # If it's a client lib error, connection might be compromised
306
- raise ConnectionError(f"Client-side error downloading stream: {e}") from e
@@ -1,280 +0,0 @@
1
- # file: autobyteus/autobyteus/rpc/client/stdio_client_connection.py
2
- import asyncio
3
- import logging
4
- import json
5
- from typing import List, Optional, Dict, Any, AsyncIterator # Added Any, AsyncIterator
6
-
7
- from autobyteus.rpc.protocol import ProtocolMessage, MessageType, ErrorCode
8
- from .abstract_client_connection import AbstractClientConnection
9
- from autobyteus.rpc.config import AgentServerConfig, TransportType # Added TransportType
10
-
11
- logger = logging.getLogger(__name__)
12
-
13
- DEFAULT_STDIO_TIMEOUT = 10.0 # seconds for a response
14
-
15
- class StdioClientConnection(AbstractClientConnection):
16
- """
17
- Client connection implementation for stdio-based Agent Servers.
18
- Manages a subprocess and communicates via its stdin/stdout using
19
- newline-delimited JSON ProtocolMessages.
20
- """
21
-
22
- def __init__(self, server_config: AgentServerConfig):
23
- """
24
- Initializes the StdioClientConnection.
25
-
26
- Args:
27
- server_config: The configuration for the stdio server.
28
-
29
- Raises:
30
- ValueError: If server_config is not for stdio or stdio_command is missing.
31
- """
32
- if server_config.transport_type != TransportType.STDIO: # Using Enum member
33
- raise ValueError("StdioClientConnection requires an AgentServerConfig with transport_type 'stdio'.")
34
- if not server_config.stdio_command:
35
- raise ValueError("AgentServerConfig for stdio transport must have a stdio_command.")
36
-
37
- super().__init__(server_id=server_config.server_id)
38
- self.server_config: AgentServerConfig = server_config
39
- self._process: Optional[asyncio.subprocess.Process] = None
40
- self._response_futures: Dict[str, asyncio.Future] = {}
41
- self._reader_task: Optional[asyncio.Task] = None
42
- self._lock = asyncio.Lock() # For managing access to _response_futures
43
-
44
- async def connect(self) -> None:
45
- """
46
- Starts the stdio server subprocess and establishes communication.
47
- """
48
- async with self._connection_lock:
49
- if self._is_connected:
50
- logger.debug(f"StdioClientConnection to '{self.server_id}' already connected.")
51
- return
52
-
53
- try:
54
- logger.info(f"Connecting StdioClientConnection to '{self.server_id}' using command: {' '.join(self.server_config.stdio_command)}")
55
- self._process = await asyncio.create_subprocess_exec(
56
- *self.server_config.stdio_command,
57
- stdin=asyncio.subprocess.PIPE,
58
- stdout=asyncio.subprocess.PIPE,
59
- stderr=asyncio.subprocess.PIPE
60
- )
61
- self._is_connected = True
62
- self._reader_task = asyncio.create_task(self._read_loop(), name=f"stdio_reader_{self.server_id}")
63
- asyncio.create_task(self._log_stderr(), name=f"stdio_stderr_logger_{self.server_id}")
64
- logger.info(f"StdioClientConnection to '{self.server_id}' connected successfully (PID: {self._process.pid}).")
65
- except Exception as e:
66
- logger.error(f"Failed to connect StdioClientConnection to '{self.server_id}': {e}", exc_info=True)
67
- self._is_connected = False
68
- if self._process and self._process.returncode is None:
69
- self._process.terminate()
70
- await self._process.wait()
71
- self._process = None
72
- raise ConnectionError(f"Failed to start or connect to stdio server '{self.server_id}': {e}") from e
73
-
74
- async def _log_stderr(self) -> None:
75
- """Logs stderr from the subprocess."""
76
- if not self._process or not self._process.stderr:
77
- return
78
-
79
- try:
80
- while self._process.returncode is None:
81
- line_bytes = await self._process.stderr.readline()
82
- if not line_bytes:
83
- if self._process.returncode is not None:
84
- break
85
- await asyncio.sleep(0.01)
86
- continue
87
-
88
- line_str = line_bytes.decode(errors='replace').strip()
89
- if line_str:
90
- logger.warning(f"StdioServer '{self.server_id}' stderr: {line_str}")
91
-
92
- if self._process.returncode is not None and self._process.stderr.at_eof():
93
- break
94
-
95
- except asyncio.CancelledError:
96
- logger.info(f"Stderr logging for '{self.server_id}' cancelled.")
97
- except Exception as e:
98
- logger.error(f"Error in stderr logging for '{self.server_id}': {e}", exc_info=True)
99
- finally:
100
- logger.debug(f"Stderr logging task for '{self.server_id}' finished.")
101
-
102
-
103
- async def _read_loop(self) -> None:
104
- """Reads messages from stdout and dispatches them."""
105
- if not self._process or not self._process.stdout:
106
- logger.error(f"StdioClientConnection '{self.server_id}' read_loop: Process or stdout not available.")
107
- return
108
-
109
- try:
110
- while self._is_connected and self._process.returncode is None:
111
- line_bytes = await self._process.stdout.readline()
112
- if not line_bytes:
113
- logger.info(f"StdioServer '{self.server_id}' stdout EOF reached. Process likely terminated.")
114
- if self._is_connected:
115
- await self._handle_unexpected_disconnect()
116
- break
117
-
118
- line_str = line_bytes.decode().strip()
119
- if not line_str:
120
- continue
121
-
122
- try:
123
- message = ProtocolMessage.from_json_str(line_str)
124
- if message.id and message.id in self._response_futures:
125
- future = self._response_futures.pop(message.id, None)
126
- if future and not future.done():
127
- future.set_result(message)
128
- elif future and future.done():
129
- logger.warning(f"Future for response ID '{message.id}' was already done. Duplicate response or late arrival?")
130
- elif message.type == MessageType.EVENT:
131
- logger.info(f"Received EVENT message via stdio (unexpected for this model): {message}")
132
- else:
133
- logger.warning(f"Received stdio message with no matching future or unhandled type: {message}")
134
- except (json.JSONDecodeError, ValueError) as e:
135
- logger.error(f"Failed to parse ProtocolMessage from stdio server '{self.server_id}': {e}. Line: '{line_str[:200]}'")
136
- except Exception as e:
137
- logger.error(f"Unexpected error processing message from stdio server '{self.server_id}': {e}. Line: '{line_str[:200]}'", exc_info=True)
138
-
139
- except asyncio.CancelledError:
140
- logger.info(f"Stdio read_loop for '{self.server_id}' cancelled.")
141
- except Exception as e:
142
- logger.error(f"Fatal error in stdio read_loop for '{self.server_id}': {e}", exc_info=True)
143
- if self._is_connected:
144
- self._handle_unexpected_disconnect()
145
- finally:
146
- logger.info(f"Stdio read_loop for '{self.server_id}' exiting.")
147
- if self._is_connected:
148
- await self._handle_unexpected_disconnect(log_warning=False)
149
-
150
- async def _handle_unexpected_disconnect(self, log_warning=True):
151
- """Handles unexpected disconnection by failing pending futures."""
152
- if log_warning:
153
- logger.warning(f"StdioClientConnection to '{self.server_id}' unexpectedly disconnected or process terminated.")
154
- self._is_connected = False
155
-
156
- # Error response is not used here, futures are set with specific errors
157
- # error_response = ProtocolMessage.create_error_response(...)
158
- async with self._lock:
159
- for msg_id, future in list(self._response_futures.items()):
160
- if not future.done():
161
- custom_error = ProtocolMessage.create_error_response(
162
- id=msg_id, code=ErrorCode.INTERNAL_ERROR,
163
- message=f"Connection lost before response for request ID {msg_id} was received."
164
- )
165
- future.set_result(custom_error)
166
- self._response_futures.pop(msg_id, None)
167
-
168
-
169
- async def close(self) -> None:
170
- """Closes the connection and terminates the subprocess."""
171
- async with self._connection_lock:
172
- if not self._is_connected and not self._process:
173
- logger.debug(f"StdioClientConnection to '{self.server_id}' already closed or never connected.")
174
- return
175
-
176
- self._is_connected = False
177
-
178
- if self._reader_task and not self._reader_task.done():
179
- self._reader_task.cancel()
180
- try:
181
- await self._reader_task
182
- except asyncio.CancelledError:
183
- pass
184
- self._reader_task = None
185
-
186
- error_on_close = ProtocolMessage.create_error_response(
187
- id=None, code=ErrorCode.INTERNAL_ERROR, message="Connection closed by client while request was pending."
188
- )
189
- for msg_id, future in list(self._response_futures.items()):
190
- if not future.done():
191
- custom_error = ProtocolMessage.create_error_response(
192
- id=msg_id, code=ErrorCode.INTERNAL_ERROR,
193
- message=f"Connection closed for request ID {msg_id} before response."
194
- )
195
- future.set_result(custom_error)
196
- self._response_futures.pop(msg_id, None)
197
-
198
-
199
- if self._process:
200
- if self._process.returncode is None:
201
- logger.info(f"Terminating stdio server process for '{self.server_id}' (PID: {self._process.pid}).")
202
- try:
203
- self._process.terminate()
204
- await asyncio.wait_for(self._process.wait(), timeout=DEFAULT_STDIO_TIMEOUT / 2)
205
- except asyncio.TimeoutError:
206
- logger.warning(f"Timeout terminating stdio server '{self.server_id}'. Killing process.")
207
- if self._process.returncode is None: self._process.kill() # Check again before kill
208
- await self._process.wait()
209
- except Exception as e:
210
- logger.error(f"Error during stdio server termination for '{self.server_id}': {e}")
211
- else:
212
- logger.info(f"Stdio server process for '{self.server_id}' (PID: {self._process.pid}) already exited with code {self._process.returncode}.")
213
- self._process = None
214
-
215
- logger.info(f"StdioClientConnection to '{self.server_id}' closed.")
216
-
217
- async def send_request(self, request_message: ProtocolMessage) -> ProtocolMessage:
218
- """Sends a request and waits for a response."""
219
- if not self._is_connected or not self._process or not self._process.stdin:
220
- # Attempt to reconnect if not connected
221
- logger.info(f"StdioClientConnection '{self.server_id}' not connected. Attempting to connect before send_request.")
222
- await self.connect()
223
- if not self._is_connected or not self._process or not self._process.stdin:
224
- raise ConnectionError(f"Failed to connect to stdio server '{self.server_id}' for send_request.")
225
-
226
- if request_message.type != MessageType.REQUEST:
227
- raise ValueError("ProtocolMessage must be of type REQUEST to be sent via send_request.")
228
- if not request_message.id:
229
- raise ValueError("Request ProtocolMessage must have an ID.")
230
-
231
- future: asyncio.Future[ProtocolMessage] = asyncio.Future()
232
- async with self._lock:
233
- self._response_futures[request_message.id] = future
234
-
235
- try:
236
- json_str = request_message.to_json_str()
237
- logger.debug(f"StdioClient '{self.server_id}' sending: {json_str}")
238
- self._process.stdin.write(json_str.encode() + b'\n')
239
- await self._process.stdin.drain()
240
- except Exception as e:
241
- async with self._lock:
242
- self._response_futures.pop(request_message.id, None)
243
- # Don't cancel future, let it timeout or be resolved by _handle_unexpected_disconnect
244
- logger.error(f"Error sending request to stdio server '{self.server_id}': {e}", exc_info=True)
245
- # If send fails, connection is likely broken. Mark as such and try to close.
246
- await self.close()
247
- raise ConnectionError(f"Failed to send request to stdio server '{self.server_id}': {e}") from e
248
-
249
- try:
250
- response = await asyncio.wait_for(future, timeout=DEFAULT_STDIO_TIMEOUT)
251
- return response
252
- except asyncio.TimeoutError:
253
- logger.warning(f"Timeout waiting for response to request ID '{request_message.id}' from stdio server '{self.server_id}'.")
254
- async with self._lock:
255
- if request_message.id in self._response_futures:
256
- self._response_futures.pop(request_message.id, None)
257
- return ProtocolMessage.create_error_response(
258
- id=request_message.id,
259
- code=ErrorCode.SERVER_ERROR_TIMEOUT,
260
- message=f"Timeout waiting for response to request ID '{request_message.id}'."
261
- )
262
- except asyncio.CancelledError:
263
- logger.info(f"Request ID '{request_message.id}' was cancelled while awaiting response.")
264
- return ProtocolMessage.create_error_response(
265
- id=request_message.id,
266
- code=ErrorCode.INTERNAL_ERROR,
267
- message=f"Request ID '{request_message.id}' cancelled."
268
- )
269
-
270
- async def request_and_download_stream(
271
- self,
272
- stream_request_params: Dict[str, Any],
273
- target_agent_id: str
274
- ) -> AsyncIterator[bytes]:
275
- logger.warning(f"StdioClientConnection does not support HTTP stream downloads for target_agent_id '{target_agent_id}'.")
276
- raise NotImplementedError("StdioClientConnection does not support HTTP stream downloads.")
277
- # This construct makes it an async generator that immediately raises
278
- if False: # pragma: no cover
279
- yield b''
280
-
@@ -1,13 +0,0 @@
1
- # file: autobyteus/autobyteus/rpc/config/__init__.py
2
- """
3
- Configuration components for the AutoByteUs RPC framework.
4
- """
5
- from .agent_server_config import AgentServerConfig
6
- from .agent_server_registry import AgentServerRegistry, default_agent_server_registry
7
-
8
- __all__ = [
9
- "AgentServerConfig",
10
- "AgentServerRegistry",
11
- "default_agent_server_registry",
12
- ]
13
-