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,141 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import logging
5
+ import ssl
6
+ from collections.abc import AsyncGenerator
7
+ from contextlib import asynccontextmanager
8
+ from typing import cast
9
+
10
+ import anyio
11
+ from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream
12
+ from mcp import ClientSession, types as mcp_types
13
+ from mcp.shared.message import SessionMessage
14
+ from pydantic import ValidationError
15
+ from websockets.asyncio.client import connect as ws_connect
16
+ from websockets.typing import Subprotocol
17
+
18
+ from .base_managed_mcp_server import BaseManagedMcpServer
19
+ from ..types import WebsocketMcpServerConfig
20
+
21
+ logger = logging.getLogger(__name__)
22
+
23
+ INITIALIZE_TIMEOUT = 10 # seconds
24
+
25
+
26
+ def _build_ssl_context(config: WebsocketMcpServerConfig) -> ssl.SSLContext | None:
27
+ """Builds an SSL context when the target URL uses wss://."""
28
+ if not config.url or not config.url.lower().startswith("wss://"):
29
+ return None
30
+
31
+ if config.verify_tls:
32
+ context = ssl.create_default_context()
33
+ if config.ca_file:
34
+ context.load_verify_locations(cafile=config.ca_file)
35
+ else:
36
+ context = ssl._create_unverified_context()
37
+
38
+ if config.client_cert:
39
+ context.load_cert_chain(certfile=config.client_cert, keyfile=config.client_key)
40
+
41
+ return context
42
+
43
+
44
+ def _normalize_subprotocols(config: WebsocketMcpServerConfig) -> list[Subprotocol]:
45
+ """Ensures the MCP subprotocol is always negotiated."""
46
+ provided = [proto for proto in config.subprotocols if proto]
47
+ lowered = {proto.lower() for proto in provided}
48
+ if "mcp" not in lowered:
49
+ provided.append("mcp")
50
+ return [Subprotocol(proto) for proto in provided]
51
+
52
+
53
+ @asynccontextmanager
54
+ async def _websocket_transport(
55
+ config: WebsocketMcpServerConfig,
56
+ ) -> AsyncGenerator[
57
+ tuple[MemoryObjectReceiveStream[SessionMessage | Exception], MemoryObjectSendStream[SessionMessage]],
58
+ None,
59
+ ]:
60
+ read_stream_writer, read_stream = anyio.create_memory_object_stream[SessionMessage | Exception](0)
61
+ write_stream, write_stream_reader = anyio.create_memory_object_stream[SessionMessage](0)
62
+
63
+ headers = dict(config.headers)
64
+ if not headers:
65
+ headers = None
66
+
67
+ connect_kwargs = {
68
+ "origin": config.origin,
69
+ "subprotocols": _normalize_subprotocols(config),
70
+ "additional_headers": headers,
71
+ "open_timeout": config.open_timeout,
72
+ "ping_interval": config.ping_interval,
73
+ "ping_timeout": config.ping_timeout,
74
+ "ssl": _build_ssl_context(config),
75
+ }
76
+ # Remove None values so websockets uses library defaults
77
+ connect_kwargs = {key: value for key, value in connect_kwargs.items() if value is not None}
78
+
79
+ negotiated_protocols = [str(proto) for proto in connect_kwargs.get("subprotocols", [])]
80
+
81
+ logger.debug(
82
+ "Connecting to MCP WebSocket %s (subprotocols=%s, origin=%s)",
83
+ config.url,
84
+ negotiated_protocols,
85
+ config.origin,
86
+ )
87
+
88
+ async with ws_connect(config.url, **connect_kwargs) as websocket:
89
+
90
+ async def ws_reader():
91
+ async with read_stream_writer:
92
+ async for raw_message in websocket:
93
+ payload = raw_message.decode("utf-8") if isinstance(raw_message, bytes) else raw_message
94
+ try:
95
+ message = mcp_types.JSONRPCMessage.model_validate_json(payload)
96
+ await read_stream_writer.send(SessionMessage(message))
97
+ except ValidationError as exc:
98
+ await read_stream_writer.send(exc)
99
+
100
+ async def ws_writer():
101
+ async with write_stream_reader:
102
+ async for session_message in write_stream_reader:
103
+ payload = session_message.message.model_dump_json(by_alias=True, exclude_none=True)
104
+ await websocket.send(payload)
105
+
106
+ async with anyio.create_task_group() as tg:
107
+ tg.start_soon(ws_reader)
108
+ tg.start_soon(ws_writer)
109
+ try:
110
+ yield read_stream, write_stream
111
+ finally:
112
+ tg.cancel_scope.cancel()
113
+
114
+
115
+ class WebsocketManagedMcpServer(BaseManagedMcpServer):
116
+ """Manages the lifecycle of a WebSocket-based MCP server connection."""
117
+
118
+ def __init__(self, config: WebsocketMcpServerConfig):
119
+ super().__init__(config)
120
+
121
+ async def _create_client_session(self) -> ClientSession:
122
+ config = cast(WebsocketMcpServerConfig, self._config)
123
+
124
+ read_stream, write_stream = await self._exit_stack.enter_async_context(
125
+ _websocket_transport(config)
126
+ )
127
+ session = await self._exit_stack.enter_async_context(ClientSession(read_stream, write_stream))
128
+
129
+ try:
130
+ await asyncio.wait_for(session.initialize(), timeout=INITIALIZE_TIMEOUT)
131
+ except asyncio.TimeoutError:
132
+ logger.error(
133
+ "Timeout occurred while initializing WebSocket session for server '%s'.",
134
+ self.server_id,
135
+ )
136
+ raise ConnectionError(
137
+ f"Server '{self.server_id}' failed to initialize within the timeout period."
138
+ ) from None
139
+
140
+ logger.debug("ClientSession established and initialized for WebSocket server '%s'.", self.server_id)
141
+ return session
@@ -7,7 +7,12 @@ from contextlib import asynccontextmanager
7
7
  from autobyteus.utils.singleton import SingletonMeta
8
8
  from autobyteus.agent.context import AgentContextRegistry
9
9
  from .config_service import McpConfigService
10
- from .server import BaseManagedMcpServer, StdioManagedMcpServer, HttpManagedMcpServer
10
+ from .server import (
11
+ BaseManagedMcpServer,
12
+ StdioManagedMcpServer,
13
+ HttpManagedMcpServer,
14
+ WebsocketManagedMcpServer,
15
+ )
11
16
  from .types import McpTransportType, McpServerInstanceKey, BaseMcpConfig, StdioMcpServerConfig
12
17
 
13
18
  logger = logging.getLogger(__name__)
@@ -29,6 +34,8 @@ class McpServerInstanceManager(metaclass=SingletonMeta):
29
34
  return StdioManagedMcpServer(server_config)
30
35
  elif server_config.transport_type == McpTransportType.STREAMABLE_HTTP:
31
36
  return HttpManagedMcpServer(server_config)
37
+ elif server_config.transport_type == McpTransportType.WEBSOCKET:
38
+ return WebsocketManagedMcpServer(server_config)
32
39
  else:
33
40
  raise NotImplementedError(f"No ManagedMcpServer implementation for transport type '{server_config.transport_type}'.")
34
41
 
@@ -41,7 +41,7 @@ class GenericMcpTool(BaseTool):
41
41
  self.get_description = self.get_instance_description
42
42
  self.get_argument_schema = self.get_instance_argument_schema
43
43
 
44
- logger.info(f"GenericMcpTool instance created for remote tool '{remote_tool_name}' on server '{self._server_id}'. "
44
+ logger.info(f"call_remote_mcp_tool instance created for remote tool '{remote_tool_name}' on server '{self._server_id}'. "
45
45
  f"Registered in AutoByteUs as '{self._instance_name}'.")
46
46
 
47
47
  # --- Getters for instance-specific data ---
@@ -51,7 +51,7 @@ class GenericMcpTool(BaseTool):
51
51
 
52
52
  # --- Base class methods (class-level, not instance-level) ---
53
53
  @classmethod
54
- def get_name(cls) -> str: return "GenericMcpTool"
54
+ def get_name(cls) -> str: return "call_remote_mcp_tool"
55
55
  @classmethod
56
56
  def get_description(cls) -> str: return "A generic wrapper for executing remote MCP tools."
57
57
  @classmethod
@@ -65,7 +65,7 @@ class GenericMcpTool(BaseTool):
65
65
  agent_id = context.agent_id
66
66
  tool_name_for_log = self.get_instance_name()
67
67
 
68
- logger.info(f"GenericMcpTool '{tool_name_for_log}': Creating proxy for agent '{agent_id}' and server '{self._server_id}'.")
68
+ logger.info(f"call_remote_mcp_tool '{tool_name_for_log}': Creating proxy for agent '{agent_id}' and server '{self._server_id}'.")
69
69
 
70
70
  try:
71
71
  # The proxy is created on-demand for each execution.
@@ -59,6 +59,8 @@ class McpToolRegistrar(metaclass=SingletonMeta):
59
59
  if server_config.tool_name_prefix:
60
60
  registered_name = f"{server_config.tool_name_prefix.rstrip('_')}_{remote_tool.name}"
61
61
 
62
+ # Note: McpToolFactory is now somewhat redundant as it holds static info,
63
+ # but we keep it for consistency. It creates a GenericMcpTool which needs this static info.
62
64
  tool_factory = McpToolFactory(
63
65
  server_id=server_config.server_id,
64
66
  remote_tool_name=remote_tool.name,
@@ -70,12 +72,13 @@ class McpToolRegistrar(metaclass=SingletonMeta):
70
72
  return ToolDefinition(
71
73
  name=registered_name,
72
74
  description=actual_desc,
73
- argument_schema=actual_arg_schema,
75
+ # Pass schema providers as lambdas to conform to the new constructor
76
+ argument_schema_provider=lambda: actual_arg_schema,
77
+ config_schema_provider=lambda: None,
74
78
  origin=ToolOrigin.MCP,
75
79
  category=server_config.server_id, # Use server_id as the category
76
80
  metadata={"mcp_server_id": server_config.server_id}, # Store origin in generic metadata
77
81
  custom_factory=tool_factory.create_tool,
78
- config_schema=None,
79
82
  tool_class=None
80
83
  )
81
84
 
@@ -10,6 +10,7 @@ class McpTransportType(str, Enum):
10
10
  """Enumeration of supported MCP transport types."""
11
11
  STDIO = "stdio"
12
12
  STREAMABLE_HTTP = "streamable_http"
13
+ WEBSOCKET = "websocket"
13
14
 
14
15
  @dataclass(frozen=True)
15
16
  class McpServerInstanceKey:
@@ -85,3 +86,63 @@ class StreamableHttpMcpServerConfig(BaseMcpConfig):
85
86
  raise ValueError(f"StreamableHttpMcpServerConfig '{self.server_id}' 'token' must be a string if provided.")
86
87
  if not isinstance(self.headers, dict) or not all(isinstance(k, str) and isinstance(v, str) for k, v in self.headers.items()):
87
88
  raise ValueError(f"StreamableHttpMcpServerConfig '{self.server_id}' 'headers' must be a Dict[str, str].")
89
+
90
+ @dataclass
91
+ class WebsocketMcpServerConfig(BaseMcpConfig):
92
+ """Configuration parameters for an MCP server using a WebSocket transport."""
93
+
94
+ url: Optional[str] = None
95
+ headers: Dict[str, str] = field(default_factory=dict)
96
+ subprotocols: List[str] = field(default_factory=list)
97
+ origin: Optional[str] = None
98
+ open_timeout: Optional[float] = 10.0
99
+ ping_interval: Optional[float] = None
100
+ ping_timeout: Optional[float] = None
101
+ verify_tls: bool = True
102
+ ca_file: Optional[str] = None
103
+ client_cert: Optional[str] = None
104
+ client_key: Optional[str] = None
105
+
106
+ def __post_init__(self):
107
+ super().__post_init__()
108
+ self.transport_type = McpTransportType.WEBSOCKET
109
+
110
+ if self.url is None or not isinstance(self.url, str) or not self.url.strip():
111
+ raise ValueError(f"WebsocketMcpServerConfig '{self.server_id}' 'url' must be a non-empty string.")
112
+
113
+ normalized_url = self.url.strip().lower()
114
+ if not (normalized_url.startswith("ws://") or normalized_url.startswith("wss://")):
115
+ raise ValueError(
116
+ f"WebsocketMcpServerConfig '{self.server_id}' 'url' must start with ws:// or wss://."
117
+ )
118
+
119
+ if not isinstance(self.headers, dict) or not all(isinstance(k, str) and isinstance(v, str) for k, v in self.headers.items()):
120
+ raise ValueError(f"WebsocketMcpServerConfig '{self.server_id}' 'headers' must be a Dict[str, str].")
121
+
122
+ if not isinstance(self.subprotocols, list) or not all(isinstance(item, str) for item in self.subprotocols):
123
+ raise ValueError(f"WebsocketMcpServerConfig '{self.server_id}' 'subprotocols' must be a list of strings.")
124
+
125
+ if self.origin is not None and not isinstance(self.origin, str):
126
+ raise ValueError(f"WebsocketMcpServerConfig '{self.server_id}' 'origin' must be a string if provided.")
127
+
128
+ for field_name in ("open_timeout", "ping_interval", "ping_timeout"):
129
+ value = getattr(self, field_name)
130
+ if value is not None and (not isinstance(value, (int, float)) or value <= 0):
131
+ raise ValueError(
132
+ f"WebsocketMcpServerConfig '{self.server_id}' '{field_name}' must be a positive number when provided."
133
+ )
134
+
135
+ if not isinstance(self.verify_tls, bool):
136
+ raise ValueError(f"WebsocketMcpServerConfig '{self.server_id}' 'verify_tls' must be a boolean.")
137
+
138
+ for path_field in ("ca_file", "client_cert", "client_key"):
139
+ path_value = getattr(self, path_field)
140
+ if path_value is not None and not isinstance(path_value, str):
141
+ raise ValueError(
142
+ f"WebsocketMcpServerConfig '{self.server_id}' '{path_field}' must be a string path when provided."
143
+ )
144
+
145
+ if self.client_key and not self.client_cert:
146
+ raise ValueError(
147
+ f"WebsocketMcpServerConfig '{self.server_id}' requires 'client_cert' when 'client_key' is provided."
148
+ )
@@ -1,10 +1,11 @@
1
1
  from .image_tools import GenerateImageTool, EditImageTool
2
2
  from .audio_tools import GenerateSpeechTool
3
3
  from .media_reader_tool import ReadMediaFile
4
-
4
+ from .download_media_tool import DownloadMediaTool
5
5
  __all__ = [
6
6
  "GenerateImageTool",
7
7
  "EditImageTool",
8
8
  "GenerateSpeechTool",
9
9
  "ReadMediaFile",
10
+ "DownloadMediaTool",
10
11
  ]
@@ -1,14 +1,38 @@
1
1
  import os
2
2
  import logging
3
- from typing import Optional, List
3
+ from typing import Optional, List, Any
4
+ from pathlib import Path
4
5
 
5
6
  from autobyteus.tools.base_tool import BaseTool
6
7
  from autobyteus.utils.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
7
8
  from autobyteus.tools.tool_category import ToolCategory
8
9
  from autobyteus.multimedia.audio import audio_client_factory, AudioModel, AudioClientFactory
10
+ from autobyteus.multimedia.audio.base_audio_client import BaseAudioClient
11
+ from autobyteus.utils.download_utils import download_file_from_url
12
+ from autobyteus.utils.file_utils import resolve_safe_path
9
13
 
10
14
  logger = logging.getLogger(__name__)
11
15
 
16
+ def _get_workspace_root(context) -> str:
17
+ if not context.workspace:
18
+ error_msg = (
19
+ f"Relative path provided, but no workspace is configured for agent '{context.agent_id}'. "
20
+ "A workspace is required to resolve relative paths."
21
+ )
22
+ logger.error(error_msg)
23
+ raise ValueError(error_msg)
24
+
25
+ base_path = context.workspace.get_base_path()
26
+ if not base_path or not isinstance(base_path, str):
27
+ error_msg = (
28
+ f"Agent '{context.agent_id}' has a configured workspace, but it provided an invalid base path "
29
+ f"('{base_path}'). Cannot resolve relative paths."
30
+ )
31
+ logger.error(error_msg)
32
+ raise ValueError(error_msg)
33
+
34
+ return base_path
35
+
12
36
 
13
37
  def _get_configured_model_identifier(env_var: str, default_model: Optional[str] = None) -> str:
14
38
  """
@@ -54,22 +78,25 @@ def _build_dynamic_audio_schema(base_params: List[ParameterDefinition], model_en
54
78
 
55
79
  class GenerateSpeechTool(BaseTool):
56
80
  """
57
-
58
81
  An agent tool for generating speech from text using a Text-to-Speech (TTS) model.
59
82
  """
60
83
  CATEGORY = ToolCategory.MULTIMEDIA
61
84
  MODEL_ENV_VAR = "DEFAULT_SPEECH_GENERATION_MODEL"
62
85
  DEFAULT_MODEL = "gemini-2.5-flash-tts"
63
86
 
87
+ def __init__(self, config=None):
88
+ super().__init__(config)
89
+ self._client: Optional[BaseAudioClient] = None
90
+
64
91
  @classmethod
65
92
  def get_name(cls) -> str:
66
- return "GenerateSpeech"
93
+ return "generate_speech"
67
94
 
68
95
  @classmethod
69
96
  def get_description(cls) -> str:
70
97
  return (
71
98
  "Generates spoken audio from text using the system's default Text-to-Speech (TTS) model. "
72
- "Returns a list of local file paths to the generated audio files (.wav) upon success."
99
+ "Saves the generated audio file (.wav or .mp3) to the specified local file path and returns the path."
73
100
  )
74
101
 
75
102
  @classmethod
@@ -82,25 +109,51 @@ class GenerateSpeechTool(BaseTool):
82
109
  "The text to be converted into spoken audio. For multi-speaker mode, you must format the prompt "
83
110
  "with speaker labels that match the speakers defined in 'speaker_mapping'. "
84
111
  "CRITICAL: Each speaker's dialogue MUST be on a new line. "
85
- "Example: 'Joe: Hello Jane.\\nJane: Hi Joe, how are you?'"
112
+ "Example: 'Joe: Hello Jane.\nJane: Hi Joe, how are you?'"
113
+ ),
114
+ required=True
115
+ ),
116
+ ParameterDefinition(
117
+ name="output_file_path",
118
+ param_type=ParameterType.STRING,
119
+ description=(
120
+ "Required. The local file path (relative to workspace) where the generated audio should be saved. "
121
+ "Example: 'assets/audio/speech.wav'"
86
122
  ),
87
123
  required=True
88
124
  )
89
125
  ]
90
126
  return _build_dynamic_audio_schema(base_params, cls.MODEL_ENV_VAR, cls.DEFAULT_MODEL)
91
127
 
92
- async def _execute(self, context, prompt: str, generation_config: Optional[dict] = None) -> List[str]:
128
+ async def _execute(
129
+ self,
130
+ context,
131
+ prompt: str,
132
+ output_file_path: str,
133
+ generation_config: Optional[dict] = None,
134
+ ) -> Any:
93
135
  model_identifier = _get_configured_model_identifier(self.MODEL_ENV_VAR, self.DEFAULT_MODEL)
94
- logger.info(f"GenerateSpeechTool executing with configured model '{model_identifier}'.")
95
- client = None
96
- try:
97
- client = audio_client_factory.create_audio_client(model_identifier=model_identifier)
98
- response = await client.generate_speech(prompt=prompt, generation_config=generation_config)
99
-
100
- if not response.audio_urls:
101
- raise ValueError("Speech generation failed to return any audio file paths.")
102
-
103
- return response.audio_urls
104
- finally:
105
- if client:
106
- await client.cleanup()
136
+ logger.info(f"generate_speech executing with configured model '{model_identifier}'.")
137
+ if self._client is None:
138
+ self._client = audio_client_factory.create_audio_client(model_identifier=model_identifier)
139
+
140
+ response = await self._client.generate_speech(prompt=prompt, generation_config=generation_config)
141
+
142
+ if not response.audio_urls:
143
+ raise ValueError("Speech generation failed to return any audio file paths.")
144
+
145
+ first_url = response.audio_urls[0]
146
+
147
+ if not output_file_path:
148
+ raise ValueError("output_file_path is required but was not provided.")
149
+
150
+ # Save to File
151
+ resolved_path = resolve_safe_path(output_file_path, _get_workspace_root(context))
152
+ await download_file_from_url(first_url, resolved_path)
153
+
154
+ return {"file_path": str(resolved_path)}
155
+
156
+ async def cleanup(self) -> None:
157
+ if self._client:
158
+ await self._client.cleanup()
159
+ self._client = None
@@ -19,18 +19,19 @@ class DownloadMediaTool(BaseTool):
19
19
  """
20
20
  A unified tool to download any media file (e.g., image, PDF, audio) from a URL.
21
21
  """
22
- CATEGORY = ToolCategory.WEB
22
+ CATEGORY = ToolCategory.MULTIMEDIA
23
23
 
24
24
  @classmethod
25
25
  def get_name(cls) -> str:
26
- return "DownloadMedia"
26
+ return "download_media"
27
27
 
28
28
  @classmethod
29
29
  def get_description(cls) -> str:
30
30
  return (
31
- "Downloads various media files (e.g., images like PNG/JPG, documents like PDF, audio like MP3/WAV) "
32
- "from a direct URL and saves them locally. It intelligently determines the correct file extension "
33
- "based on the content type. Returns the absolute path to the downloaded file."
31
+ "Download a media file (image/PDF/audio/etc.) from a direct URL and save it locally. "
32
+ "The tool picks the correct file extension from the HTTP Content-Type header (or falls back to the URL). "
33
+ "Files are saved to the agent workspace if you give a relative folder (preferred), or to your default "
34
+ "Downloads directory when no folder is provided. Returns the absolute path of the saved file."
34
35
  )
35
36
 
36
37
  @classmethod
@@ -62,8 +63,21 @@ class DownloadMediaTool(BaseTool):
62
63
  if folder:
63
64
  # Security: prevent path traversal attacks.
64
65
  if ".." in folder:
65
- raise ValueError("Security error: 'folder' path cannot contain '..'.")
66
- destination_dir = os.path.abspath(folder)
66
+ raise ValueError("Security error: 'folder' path cannot contain '..'.")
67
+ if not os.path.isabs(folder):
68
+ workspace = context.workspace
69
+ # Prefer workspace base path when available to keep downloads inside the agent's sandbox.
70
+ if workspace and hasattr(workspace, "get_base_path") and callable(getattr(workspace, "get_base_path")):
71
+ base_path = os.path.abspath(workspace.get_base_path())
72
+ destination_dir = os.path.abspath(os.path.join(base_path, folder))
73
+ # Ensure resolved path stays within workspace
74
+ if os.path.commonpath([base_path]) != os.path.commonpath([base_path, destination_dir]):
75
+ raise ValueError(f"Security error: 'folder' resolves outside workspace: {destination_dir}")
76
+ else:
77
+ # Fallback: resolve relative folder under the default download directory
78
+ destination_dir = os.path.abspath(os.path.join(get_default_download_folder(), folder))
79
+ else:
80
+ destination_dir = os.path.abspath(folder)
67
81
  else:
68
82
  destination_dir = get_default_download_folder()
69
83