autobyteus 1.2.1__py3-none-any.whl → 1.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (472) hide show
  1. autobyteus/agent/agent.py +15 -5
  2. autobyteus/agent/bootstrap_steps/__init__.py +3 -3
  3. autobyteus/agent/bootstrap_steps/agent_bootstrapper.py +5 -59
  4. autobyteus/agent/bootstrap_steps/base_bootstrap_step.py +1 -4
  5. autobyteus/agent/bootstrap_steps/mcp_server_prewarming_step.py +1 -3
  6. autobyteus/agent/bootstrap_steps/system_prompt_processing_step.py +16 -13
  7. autobyteus/agent/bootstrap_steps/working_context_snapshot_restore_step.py +38 -0
  8. autobyteus/agent/bootstrap_steps/workspace_context_initialization_step.py +2 -4
  9. autobyteus/agent/context/agent_config.py +47 -20
  10. autobyteus/agent/context/agent_context.py +23 -18
  11. autobyteus/agent/context/agent_runtime_state.py +21 -19
  12. autobyteus/agent/events/__init__.py +16 -1
  13. autobyteus/agent/events/agent_events.py +43 -3
  14. autobyteus/agent/events/agent_input_event_queue_manager.py +79 -26
  15. autobyteus/agent/events/event_store.py +57 -0
  16. autobyteus/agent/events/notifiers.py +69 -59
  17. autobyteus/agent/events/worker_event_dispatcher.py +21 -64
  18. autobyteus/agent/factory/agent_factory.py +83 -6
  19. autobyteus/agent/handlers/__init__.py +2 -0
  20. autobyteus/agent/handlers/approved_tool_invocation_event_handler.py +51 -34
  21. autobyteus/agent/handlers/bootstrap_event_handler.py +155 -0
  22. autobyteus/agent/handlers/inter_agent_message_event_handler.py +10 -0
  23. autobyteus/agent/handlers/lifecycle_event_logger.py +19 -11
  24. autobyteus/agent/handlers/llm_complete_response_received_event_handler.py +10 -15
  25. autobyteus/agent/handlers/llm_user_message_ready_event_handler.py +188 -48
  26. autobyteus/agent/handlers/tool_execution_approval_event_handler.py +0 -10
  27. autobyteus/agent/handlers/tool_invocation_request_event_handler.py +53 -48
  28. autobyteus/agent/handlers/tool_result_event_handler.py +7 -8
  29. autobyteus/agent/handlers/user_input_message_event_handler.py +10 -3
  30. autobyteus/agent/input_processor/memory_ingest_input_processor.py +44 -0
  31. autobyteus/agent/lifecycle/__init__.py +12 -0
  32. autobyteus/agent/lifecycle/base_processor.py +109 -0
  33. autobyteus/agent/lifecycle/events.py +35 -0
  34. autobyteus/agent/lifecycle/processor_definition.py +36 -0
  35. autobyteus/agent/lifecycle/processor_registry.py +106 -0
  36. autobyteus/agent/llm_request_assembler.py +98 -0
  37. autobyteus/agent/llm_response_processor/__init__.py +1 -8
  38. autobyteus/agent/message/context_file_type.py +1 -1
  39. autobyteus/agent/runtime/agent_runtime.py +29 -21
  40. autobyteus/agent/runtime/agent_worker.py +98 -19
  41. autobyteus/agent/shutdown_steps/__init__.py +2 -0
  42. autobyteus/agent/shutdown_steps/agent_shutdown_orchestrator.py +2 -0
  43. autobyteus/agent/shutdown_steps/tool_cleanup_step.py +58 -0
  44. autobyteus/agent/status/__init__.py +14 -0
  45. autobyteus/agent/status/manager.py +93 -0
  46. autobyteus/agent/status/status_deriver.py +96 -0
  47. autobyteus/agent/{phases/phase_enum.py → status/status_enum.py} +16 -16
  48. autobyteus/agent/status/status_update_utils.py +73 -0
  49. autobyteus/agent/streaming/__init__.py +52 -5
  50. autobyteus/agent/streaming/adapters/__init__.py +18 -0
  51. autobyteus/agent/streaming/adapters/invocation_adapter.py +184 -0
  52. autobyteus/agent/streaming/adapters/tool_call_parsing.py +163 -0
  53. autobyteus/agent/streaming/adapters/tool_syntax_registry.py +67 -0
  54. autobyteus/agent/streaming/agent_event_stream.py +3 -183
  55. autobyteus/agent/streaming/api_tool_call/__init__.py +16 -0
  56. autobyteus/agent/streaming/api_tool_call/file_content_streamer.py +56 -0
  57. autobyteus/agent/streaming/api_tool_call/json_string_field_extractor.py +175 -0
  58. autobyteus/agent/streaming/api_tool_call_streaming_response_handler.py +4 -0
  59. autobyteus/agent/streaming/events/__init__.py +6 -0
  60. autobyteus/agent/streaming/events/stream_event_payloads.py +284 -0
  61. autobyteus/agent/streaming/events/stream_events.py +141 -0
  62. autobyteus/agent/streaming/handlers/__init__.py +15 -0
  63. autobyteus/agent/streaming/handlers/api_tool_call_streaming_response_handler.py +303 -0
  64. autobyteus/agent/streaming/handlers/parsing_streaming_response_handler.py +107 -0
  65. autobyteus/agent/streaming/handlers/pass_through_streaming_response_handler.py +107 -0
  66. autobyteus/agent/streaming/handlers/streaming_handler_factory.py +177 -0
  67. autobyteus/agent/streaming/handlers/streaming_response_handler.py +58 -0
  68. autobyteus/agent/streaming/parser/__init__.py +61 -0
  69. autobyteus/agent/streaming/parser/event_emitter.py +181 -0
  70. autobyteus/agent/streaming/parser/events.py +4 -0
  71. autobyteus/agent/streaming/parser/invocation_adapter.py +4 -0
  72. autobyteus/agent/streaming/parser/json_parsing_strategies/__init__.py +19 -0
  73. autobyteus/agent/streaming/parser/json_parsing_strategies/base.py +32 -0
  74. autobyteus/agent/streaming/parser/json_parsing_strategies/default.py +34 -0
  75. autobyteus/agent/streaming/parser/json_parsing_strategies/gemini.py +31 -0
  76. autobyteus/agent/streaming/parser/json_parsing_strategies/openai.py +64 -0
  77. autobyteus/agent/streaming/parser/json_parsing_strategies/registry.py +75 -0
  78. autobyteus/agent/streaming/parser/parser_context.py +227 -0
  79. autobyteus/agent/streaming/parser/parser_factory.py +132 -0
  80. autobyteus/agent/streaming/parser/sentinel_format.py +7 -0
  81. autobyteus/agent/streaming/parser/state_factory.py +62 -0
  82. autobyteus/agent/streaming/parser/states/__init__.py +1 -0
  83. autobyteus/agent/streaming/parser/states/base_state.py +60 -0
  84. autobyteus/agent/streaming/parser/states/custom_xml_tag_run_bash_parsing_state.py +38 -0
  85. autobyteus/agent/streaming/parser/states/custom_xml_tag_write_file_parsing_state.py +55 -0
  86. autobyteus/agent/streaming/parser/states/delimited_content_state.py +146 -0
  87. autobyteus/agent/streaming/parser/states/json_initialization_state.py +144 -0
  88. autobyteus/agent/streaming/parser/states/json_tool_parsing_state.py +137 -0
  89. autobyteus/agent/streaming/parser/states/sentinel_content_state.py +30 -0
  90. autobyteus/agent/streaming/parser/states/sentinel_initialization_state.py +117 -0
  91. autobyteus/agent/streaming/parser/states/text_state.py +78 -0
  92. autobyteus/agent/streaming/parser/states/xml_patch_file_tool_parsing_state.py +328 -0
  93. autobyteus/agent/streaming/parser/states/xml_run_bash_tool_parsing_state.py +129 -0
  94. autobyteus/agent/streaming/parser/states/xml_tag_initialization_state.py +151 -0
  95. autobyteus/agent/streaming/parser/states/xml_tool_parsing_state.py +63 -0
  96. autobyteus/agent/streaming/parser/states/xml_write_file_tool_parsing_state.py +343 -0
  97. autobyteus/agent/streaming/parser/strategies/__init__.py +17 -0
  98. autobyteus/agent/streaming/parser/strategies/base.py +24 -0
  99. autobyteus/agent/streaming/parser/strategies/json_tool_strategy.py +26 -0
  100. autobyteus/agent/streaming/parser/strategies/registry.py +28 -0
  101. autobyteus/agent/streaming/parser/strategies/sentinel_strategy.py +23 -0
  102. autobyteus/agent/streaming/parser/strategies/xml_tag_strategy.py +21 -0
  103. autobyteus/agent/streaming/parser/stream_scanner.py +167 -0
  104. autobyteus/agent/streaming/parser/streaming_parser.py +212 -0
  105. autobyteus/agent/streaming/parser/tool_call_parsing.py +4 -0
  106. autobyteus/agent/streaming/parser/tool_constants.py +7 -0
  107. autobyteus/agent/streaming/parser/tool_syntax_registry.py +4 -0
  108. autobyteus/agent/streaming/parser/xml_tool_parsing_state_registry.py +55 -0
  109. autobyteus/agent/streaming/parsing_streaming_response_handler.py +4 -0
  110. autobyteus/agent/streaming/pass_through_streaming_response_handler.py +4 -0
  111. autobyteus/agent/streaming/queue_streamer.py +3 -57
  112. autobyteus/agent/streaming/segments/__init__.py +5 -0
  113. autobyteus/agent/streaming/segments/segment_events.py +82 -0
  114. autobyteus/agent/streaming/stream_event_payloads.py +2 -223
  115. autobyteus/agent/streaming/stream_events.py +3 -140
  116. autobyteus/agent/streaming/streaming_handler_factory.py +4 -0
  117. autobyteus/agent/streaming/streaming_response_handler.py +4 -0
  118. autobyteus/agent/streaming/streams/__init__.py +5 -0
  119. autobyteus/agent/streaming/streams/agent_event_stream.py +197 -0
  120. autobyteus/agent/streaming/utils/__init__.py +5 -0
  121. autobyteus/agent/streaming/utils/queue_streamer.py +59 -0
  122. autobyteus/agent/system_prompt_processor/__init__.py +2 -0
  123. autobyteus/agent/system_prompt_processor/available_skills_processor.py +96 -0
  124. autobyteus/agent/system_prompt_processor/base_processor.py +1 -1
  125. autobyteus/agent/system_prompt_processor/processor_meta.py +15 -2
  126. autobyteus/agent/system_prompt_processor/tool_manifest_injector_processor.py +39 -58
  127. autobyteus/agent/token_budget.py +56 -0
  128. autobyteus/agent/tool_execution_result_processor/memory_ingest_tool_result_processor.py +29 -0
  129. autobyteus/agent/tool_invocation.py +16 -40
  130. autobyteus/agent/tool_invocation_preprocessor/__init__.py +9 -0
  131. autobyteus/agent/tool_invocation_preprocessor/base_preprocessor.py +45 -0
  132. autobyteus/agent/tool_invocation_preprocessor/processor_definition.py +15 -0
  133. autobyteus/agent/tool_invocation_preprocessor/processor_meta.py +33 -0
  134. autobyteus/agent/tool_invocation_preprocessor/processor_registry.py +60 -0
  135. autobyteus/agent/utils/wait_for_idle.py +12 -14
  136. autobyteus/agent/workspace/base_workspace.py +6 -27
  137. autobyteus/agent_team/agent_team.py +3 -3
  138. autobyteus/agent_team/agent_team_builder.py +1 -41
  139. autobyteus/agent_team/bootstrap_steps/__init__.py +0 -4
  140. autobyteus/agent_team/bootstrap_steps/agent_configuration_preparation_step.py +8 -18
  141. autobyteus/agent_team/bootstrap_steps/agent_team_bootstrapper.py +4 -16
  142. autobyteus/agent_team/bootstrap_steps/base_agent_team_bootstrap_step.py +1 -2
  143. autobyteus/agent_team/bootstrap_steps/coordinator_initialization_step.py +1 -2
  144. autobyteus/agent_team/bootstrap_steps/task_notifier_initialization_step.py +1 -2
  145. autobyteus/agent_team/bootstrap_steps/team_context_initialization_step.py +4 -4
  146. autobyteus/agent_team/context/agent_team_config.py +6 -3
  147. autobyteus/agent_team/context/agent_team_context.py +25 -3
  148. autobyteus/agent_team/context/agent_team_runtime_state.py +9 -6
  149. autobyteus/agent_team/events/__init__.py +11 -0
  150. autobyteus/agent_team/events/agent_team_event_dispatcher.py +22 -9
  151. autobyteus/agent_team/events/agent_team_events.py +16 -0
  152. autobyteus/agent_team/events/event_store.py +57 -0
  153. autobyteus/agent_team/factory/agent_team_factory.py +8 -0
  154. autobyteus/agent_team/handlers/inter_agent_message_request_event_handler.py +18 -2
  155. autobyteus/agent_team/handlers/lifecycle_agent_team_event_handler.py +21 -5
  156. autobyteus/agent_team/handlers/process_user_message_event_handler.py +17 -8
  157. autobyteus/agent_team/handlers/tool_approval_team_event_handler.py +19 -4
  158. autobyteus/agent_team/runtime/agent_team_runtime.py +41 -10
  159. autobyteus/agent_team/runtime/agent_team_worker.py +69 -5
  160. autobyteus/agent_team/status/__init__.py +14 -0
  161. autobyteus/agent_team/status/agent_team_status.py +18 -0
  162. autobyteus/agent_team/status/agent_team_status_manager.py +33 -0
  163. autobyteus/agent_team/status/status_deriver.py +62 -0
  164. autobyteus/agent_team/status/status_update_utils.py +42 -0
  165. autobyteus/agent_team/streaming/__init__.py +2 -2
  166. autobyteus/agent_team/streaming/agent_team_event_notifier.py +6 -6
  167. autobyteus/agent_team/streaming/agent_team_stream_event_payloads.py +4 -4
  168. autobyteus/agent_team/streaming/agent_team_stream_events.py +3 -3
  169. autobyteus/agent_team/system_prompt_processor/__init__.py +6 -0
  170. autobyteus/agent_team/system_prompt_processor/team_manifest_injector_processor.py +76 -0
  171. autobyteus/agent_team/task_notification/task_notification_mode.py +19 -0
  172. autobyteus/agent_team/utils/wait_for_idle.py +4 -4
  173. autobyteus/cli/agent_cli.py +18 -10
  174. autobyteus/cli/agent_team_tui/app.py +14 -11
  175. autobyteus/cli/agent_team_tui/state.py +13 -15
  176. autobyteus/cli/agent_team_tui/widgets/agent_list_sidebar.py +15 -15
  177. autobyteus/cli/agent_team_tui/widgets/focus_pane.py +143 -36
  178. autobyteus/cli/agent_team_tui/widgets/renderables.py +1 -1
  179. autobyteus/cli/agent_team_tui/widgets/shared.py +25 -25
  180. autobyteus/cli/cli_display.py +193 -44
  181. autobyteus/cli/workflow_tui/app.py +9 -10
  182. autobyteus/cli/workflow_tui/state.py +14 -16
  183. autobyteus/cli/workflow_tui/widgets/agent_list_sidebar.py +15 -15
  184. autobyteus/cli/workflow_tui/widgets/focus_pane.py +137 -35
  185. autobyteus/cli/workflow_tui/widgets/renderables.py +1 -1
  186. autobyteus/cli/workflow_tui/widgets/shared.py +25 -25
  187. autobyteus/clients/autobyteus_client.py +94 -1
  188. autobyteus/events/event_types.py +11 -18
  189. autobyteus/llm/api/autobyteus_llm.py +33 -29
  190. autobyteus/llm/api/claude_llm.py +142 -36
  191. autobyteus/llm/api/gemini_llm.py +163 -59
  192. autobyteus/llm/api/grok_llm.py +1 -1
  193. autobyteus/llm/api/minimax_llm.py +26 -0
  194. autobyteus/llm/api/mistral_llm.py +113 -87
  195. autobyteus/llm/api/ollama_llm.py +9 -42
  196. autobyteus/llm/api/openai_compatible_llm.py +127 -91
  197. autobyteus/llm/api/openai_llm.py +3 -3
  198. autobyteus/llm/api/openai_responses_llm.py +324 -0
  199. autobyteus/llm/api/zhipu_llm.py +21 -2
  200. autobyteus/llm/autobyteus_provider.py +70 -60
  201. autobyteus/llm/base_llm.py +85 -81
  202. autobyteus/llm/converters/__init__.py +14 -0
  203. autobyteus/llm/converters/anthropic_tool_call_converter.py +37 -0
  204. autobyteus/llm/converters/gemini_tool_call_converter.py +57 -0
  205. autobyteus/llm/converters/mistral_tool_call_converter.py +37 -0
  206. autobyteus/llm/converters/openai_tool_call_converter.py +38 -0
  207. autobyteus/llm/extensions/base_extension.py +6 -12
  208. autobyteus/llm/extensions/token_usage_tracking_extension.py +45 -18
  209. autobyteus/llm/llm_factory.py +282 -204
  210. autobyteus/llm/lmstudio_provider.py +60 -49
  211. autobyteus/llm/models.py +35 -2
  212. autobyteus/llm/ollama_provider.py +60 -49
  213. autobyteus/llm/ollama_provider_resolver.py +0 -1
  214. autobyteus/llm/prompt_renderers/__init__.py +19 -0
  215. autobyteus/llm/prompt_renderers/anthropic_prompt_renderer.py +104 -0
  216. autobyteus/llm/prompt_renderers/autobyteus_prompt_renderer.py +19 -0
  217. autobyteus/llm/prompt_renderers/base_prompt_renderer.py +10 -0
  218. autobyteus/llm/prompt_renderers/gemini_prompt_renderer.py +63 -0
  219. autobyteus/llm/prompt_renderers/mistral_prompt_renderer.py +87 -0
  220. autobyteus/llm/prompt_renderers/ollama_prompt_renderer.py +51 -0
  221. autobyteus/llm/prompt_renderers/openai_chat_renderer.py +97 -0
  222. autobyteus/llm/prompt_renderers/openai_responses_renderer.py +101 -0
  223. autobyteus/llm/providers.py +1 -3
  224. autobyteus/llm/token_counter/claude_token_counter.py +56 -25
  225. autobyteus/llm/token_counter/mistral_token_counter.py +12 -8
  226. autobyteus/llm/token_counter/openai_token_counter.py +24 -5
  227. autobyteus/llm/token_counter/token_counter_factory.py +12 -5
  228. autobyteus/llm/utils/llm_config.py +6 -12
  229. autobyteus/llm/utils/media_payload_formatter.py +27 -20
  230. autobyteus/llm/utils/messages.py +55 -3
  231. autobyteus/llm/utils/response_types.py +3 -0
  232. autobyteus/llm/utils/tool_call_delta.py +31 -0
  233. autobyteus/memory/__init__.py +35 -0
  234. autobyteus/memory/compaction/__init__.py +9 -0
  235. autobyteus/memory/compaction/compaction_result.py +8 -0
  236. autobyteus/memory/compaction/compactor.py +89 -0
  237. autobyteus/memory/compaction/summarizer.py +11 -0
  238. autobyteus/memory/compaction_snapshot_builder.py +84 -0
  239. autobyteus/memory/memory_manager.py +205 -0
  240. autobyteus/memory/models/__init__.py +14 -0
  241. autobyteus/memory/models/episodic_item.py +41 -0
  242. autobyteus/memory/models/memory_types.py +7 -0
  243. autobyteus/memory/models/raw_trace_item.py +79 -0
  244. autobyteus/memory/models/semantic_item.py +41 -0
  245. autobyteus/memory/models/tool_interaction.py +20 -0
  246. autobyteus/memory/path_resolver.py +27 -0
  247. autobyteus/memory/policies/__init__.py +5 -0
  248. autobyteus/memory/policies/compaction_policy.py +16 -0
  249. autobyteus/memory/restore/__init__.py +1 -0
  250. autobyteus/memory/restore/working_context_snapshot_bootstrapper.py +61 -0
  251. autobyteus/memory/retrieval/__init__.py +7 -0
  252. autobyteus/memory/retrieval/memory_bundle.py +11 -0
  253. autobyteus/memory/retrieval/retriever.py +13 -0
  254. autobyteus/memory/store/__init__.py +9 -0
  255. autobyteus/memory/store/base_store.py +14 -0
  256. autobyteus/memory/store/file_store.py +98 -0
  257. autobyteus/memory/store/working_context_snapshot_store.py +28 -0
  258. autobyteus/memory/tool_interaction_builder.py +46 -0
  259. autobyteus/memory/turn_tracker.py +9 -0
  260. autobyteus/memory/working_context_snapshot.py +69 -0
  261. autobyteus/memory/working_context_snapshot_serializer.py +135 -0
  262. autobyteus/multimedia/audio/api/autobyteus_audio_client.py +19 -5
  263. autobyteus/multimedia/audio/api/gemini_audio_client.py +109 -16
  264. autobyteus/multimedia/audio/audio_client_factory.py +47 -9
  265. autobyteus/multimedia/audio/audio_model.py +2 -1
  266. autobyteus/multimedia/image/api/autobyteus_image_client.py +19 -5
  267. autobyteus/multimedia/image/api/gemini_image_client.py +39 -17
  268. autobyteus/multimedia/image/api/openai_image_client.py +125 -43
  269. autobyteus/multimedia/image/autobyteus_image_provider.py +2 -1
  270. autobyteus/multimedia/image/image_client_factory.py +47 -15
  271. autobyteus/multimedia/image/image_model.py +5 -2
  272. autobyteus/multimedia/providers.py +3 -2
  273. autobyteus/skills/loader.py +71 -0
  274. autobyteus/skills/model.py +11 -0
  275. autobyteus/skills/registry.py +70 -0
  276. autobyteus/task_management/tools/todo_tools/add_todo.py +2 -2
  277. autobyteus/task_management/tools/todo_tools/create_todo_list.py +2 -2
  278. autobyteus/task_management/tools/todo_tools/update_todo_status.py +2 -2
  279. autobyteus/tools/__init__.py +34 -47
  280. autobyteus/tools/base_tool.py +7 -0
  281. autobyteus/tools/file/__init__.py +2 -6
  282. autobyteus/tools/file/patch_file.py +149 -0
  283. autobyteus/tools/file/read_file.py +36 -5
  284. autobyteus/tools/file/write_file.py +4 -1
  285. autobyteus/tools/functional_tool.py +43 -6
  286. autobyteus/tools/mcp/__init__.py +2 -0
  287. autobyteus/tools/mcp/config_service.py +5 -1
  288. autobyteus/tools/mcp/server/__init__.py +2 -0
  289. autobyteus/tools/mcp/server/http_managed_mcp_server.py +1 -1
  290. autobyteus/tools/mcp/server/websocket_managed_mcp_server.py +141 -0
  291. autobyteus/tools/mcp/server_instance_manager.py +8 -1
  292. autobyteus/tools/mcp/types.py +61 -0
  293. autobyteus/tools/multimedia/audio_tools.py +70 -17
  294. autobyteus/tools/multimedia/download_media_tool.py +18 -4
  295. autobyteus/tools/multimedia/image_tools.py +246 -62
  296. autobyteus/tools/operation_executor/journal_manager.py +107 -0
  297. autobyteus/tools/operation_executor/operation_event_buffer.py +57 -0
  298. autobyteus/tools/operation_executor/operation_event_producer.py +29 -0
  299. autobyteus/tools/operation_executor/operation_executor.py +58 -0
  300. autobyteus/tools/registry/tool_definition.py +43 -2
  301. autobyteus/tools/skill/load_skill.py +50 -0
  302. autobyteus/tools/terminal/__init__.py +45 -0
  303. autobyteus/tools/terminal/ansi_utils.py +32 -0
  304. autobyteus/tools/terminal/background_process_manager.py +233 -0
  305. autobyteus/tools/terminal/output_buffer.py +105 -0
  306. autobyteus/tools/terminal/prompt_detector.py +63 -0
  307. autobyteus/tools/terminal/pty_session.py +241 -0
  308. autobyteus/tools/terminal/session_factory.py +20 -0
  309. autobyteus/tools/terminal/terminal_session_manager.py +226 -0
  310. autobyteus/tools/terminal/tools/__init__.py +13 -0
  311. autobyteus/tools/terminal/tools/get_process_output.py +81 -0
  312. autobyteus/tools/terminal/tools/run_bash.py +109 -0
  313. autobyteus/tools/terminal/tools/start_background_process.py +104 -0
  314. autobyteus/tools/terminal/tools/stop_background_process.py +67 -0
  315. autobyteus/tools/terminal/types.py +54 -0
  316. autobyteus/tools/terminal/wsl_tmux_session.py +221 -0
  317. autobyteus/tools/terminal/wsl_utils.py +156 -0
  318. autobyteus/tools/transaction_management/backup_handler.py +48 -0
  319. autobyteus/tools/transaction_management/operation_lifecycle_manager.py +62 -0
  320. autobyteus/tools/usage/__init__.py +1 -2
  321. autobyteus/tools/usage/formatters/__init__.py +17 -1
  322. autobyteus/tools/usage/formatters/base_formatter.py +8 -0
  323. autobyteus/tools/usage/formatters/default_xml_schema_formatter.py +2 -2
  324. autobyteus/tools/usage/formatters/mistral_json_schema_formatter.py +18 -0
  325. autobyteus/tools/usage/formatters/patch_file_xml_example_formatter.py +64 -0
  326. autobyteus/tools/usage/formatters/patch_file_xml_schema_formatter.py +31 -0
  327. autobyteus/tools/usage/formatters/run_bash_xml_example_formatter.py +32 -0
  328. autobyteus/tools/usage/formatters/run_bash_xml_schema_formatter.py +36 -0
  329. autobyteus/tools/usage/formatters/write_file_xml_example_formatter.py +53 -0
  330. autobyteus/tools/usage/formatters/write_file_xml_schema_formatter.py +31 -0
  331. autobyteus/tools/usage/providers/tool_manifest_provider.py +10 -10
  332. autobyteus/tools/usage/registries/__init__.py +1 -3
  333. autobyteus/tools/usage/registries/tool_formatting_registry.py +115 -8
  334. autobyteus/tools/usage/tool_schema_provider.py +51 -0
  335. autobyteus/tools/web/__init__.py +4 -0
  336. autobyteus/tools/web/read_url_tool.py +80 -0
  337. autobyteus/utils/diff_utils.py +271 -0
  338. autobyteus/utils/download_utils.py +109 -0
  339. autobyteus/utils/file_utils.py +57 -2
  340. autobyteus/utils/gemini_helper.py +64 -0
  341. autobyteus/utils/gemini_model_mapping.py +71 -0
  342. autobyteus/utils/llm_output_formatter.py +75 -0
  343. autobyteus/utils/tool_call_format.py +36 -0
  344. autobyteus/workflow/agentic_workflow.py +3 -3
  345. autobyteus/workflow/bootstrap_steps/agent_tool_injection_step.py +2 -2
  346. autobyteus/workflow/bootstrap_steps/base_workflow_bootstrap_step.py +2 -2
  347. autobyteus/workflow/bootstrap_steps/coordinator_initialization_step.py +2 -2
  348. autobyteus/workflow/bootstrap_steps/coordinator_prompt_preparation_step.py +3 -9
  349. autobyteus/workflow/bootstrap_steps/workflow_bootstrapper.py +6 -6
  350. autobyteus/workflow/bootstrap_steps/workflow_runtime_queue_initialization_step.py +2 -2
  351. autobyteus/workflow/context/workflow_context.py +3 -3
  352. autobyteus/workflow/context/workflow_runtime_state.py +5 -5
  353. autobyteus/workflow/events/workflow_event_dispatcher.py +5 -5
  354. autobyteus/workflow/handlers/lifecycle_workflow_event_handler.py +3 -3
  355. autobyteus/workflow/handlers/process_user_message_event_handler.py +5 -5
  356. autobyteus/workflow/handlers/tool_approval_workflow_event_handler.py +2 -2
  357. autobyteus/workflow/runtime/workflow_runtime.py +8 -8
  358. autobyteus/workflow/runtime/workflow_worker.py +3 -3
  359. autobyteus/workflow/status/__init__.py +11 -0
  360. autobyteus/workflow/status/workflow_status.py +19 -0
  361. autobyteus/workflow/status/workflow_status_manager.py +48 -0
  362. autobyteus/workflow/streaming/__init__.py +2 -2
  363. autobyteus/workflow/streaming/workflow_event_notifier.py +7 -7
  364. autobyteus/workflow/streaming/workflow_stream_event_payloads.py +4 -4
  365. autobyteus/workflow/streaming/workflow_stream_events.py +3 -3
  366. autobyteus/workflow/utils/wait_for_idle.py +4 -4
  367. autobyteus-1.3.0.dist-info/METADATA +293 -0
  368. autobyteus-1.3.0.dist-info/RECORD +606 -0
  369. {autobyteus-1.2.1.dist-info → autobyteus-1.3.0.dist-info}/WHEEL +1 -1
  370. {autobyteus-1.2.1.dist-info → autobyteus-1.3.0.dist-info}/top_level.txt +0 -1
  371. autobyteus/agent/bootstrap_steps/agent_runtime_queue_initialization_step.py +0 -57
  372. autobyteus/agent/hooks/__init__.py +0 -16
  373. autobyteus/agent/hooks/base_phase_hook.py +0 -78
  374. autobyteus/agent/hooks/hook_definition.py +0 -36
  375. autobyteus/agent/hooks/hook_meta.py +0 -37
  376. autobyteus/agent/hooks/hook_registry.py +0 -106
  377. autobyteus/agent/llm_response_processor/provider_aware_tool_usage_processor.py +0 -103
  378. autobyteus/agent/phases/__init__.py +0 -18
  379. autobyteus/agent/phases/discover.py +0 -53
  380. autobyteus/agent/phases/manager.py +0 -265
  381. autobyteus/agent/phases/transition_decorator.py +0 -40
  382. autobyteus/agent/phases/transition_info.py +0 -33
  383. autobyteus/agent/remote_agent.py +0 -244
  384. autobyteus/agent/workspace/workspace_definition.py +0 -36
  385. autobyteus/agent/workspace/workspace_meta.py +0 -37
  386. autobyteus/agent/workspace/workspace_registry.py +0 -72
  387. autobyteus/agent_team/bootstrap_steps/agent_team_runtime_queue_initialization_step.py +0 -25
  388. autobyteus/agent_team/bootstrap_steps/coordinator_prompt_preparation_step.py +0 -85
  389. autobyteus/agent_team/phases/__init__.py +0 -11
  390. autobyteus/agent_team/phases/agent_team_operational_phase.py +0 -19
  391. autobyteus/agent_team/phases/agent_team_phase_manager.py +0 -48
  392. autobyteus/llm/api/bedrock_llm.py +0 -92
  393. autobyteus/llm/api/groq_llm.py +0 -94
  394. autobyteus/llm/api/nvidia_llm.py +0 -108
  395. autobyteus/llm/utils/token_pricing_config.py +0 -87
  396. autobyteus/rpc/__init__.py +0 -73
  397. autobyteus/rpc/client/__init__.py +0 -17
  398. autobyteus/rpc/client/abstract_client_connection.py +0 -124
  399. autobyteus/rpc/client/client_connection_manager.py +0 -153
  400. autobyteus/rpc/client/sse_client_connection.py +0 -306
  401. autobyteus/rpc/client/stdio_client_connection.py +0 -280
  402. autobyteus/rpc/config/__init__.py +0 -13
  403. autobyteus/rpc/config/agent_server_config.py +0 -153
  404. autobyteus/rpc/config/agent_server_registry.py +0 -152
  405. autobyteus/rpc/hosting.py +0 -244
  406. autobyteus/rpc/protocol.py +0 -244
  407. autobyteus/rpc/server/__init__.py +0 -20
  408. autobyteus/rpc/server/agent_server_endpoint.py +0 -181
  409. autobyteus/rpc/server/base_method_handler.py +0 -40
  410. autobyteus/rpc/server/method_handlers.py +0 -259
  411. autobyteus/rpc/server/sse_server_handler.py +0 -182
  412. autobyteus/rpc/server/stdio_server_handler.py +0 -151
  413. autobyteus/rpc/server_main.py +0 -198
  414. autobyteus/rpc/transport_type.py +0 -13
  415. autobyteus/tools/bash/__init__.py +0 -2
  416. autobyteus/tools/bash/bash_executor.py +0 -100
  417. autobyteus/tools/browser/__init__.py +0 -2
  418. autobyteus/tools/browser/session_aware/browser_session_aware_navigate_to.py +0 -75
  419. autobyteus/tools/browser/session_aware/browser_session_aware_tool.py +0 -30
  420. autobyteus/tools/browser/session_aware/browser_session_aware_web_element_trigger.py +0 -154
  421. autobyteus/tools/browser/session_aware/browser_session_aware_webpage_reader.py +0 -89
  422. autobyteus/tools/browser/session_aware/browser_session_aware_webpage_screenshot_taker.py +0 -107
  423. autobyteus/tools/browser/session_aware/factory/browser_session_aware_web_element_trigger_factory.py +0 -14
  424. autobyteus/tools/browser/session_aware/factory/browser_session_aware_webpage_reader_factory.py +0 -26
  425. autobyteus/tools/browser/session_aware/factory/browser_session_aware_webpage_screenshot_taker_factory.py +0 -14
  426. autobyteus/tools/browser/session_aware/shared_browser_session.py +0 -11
  427. autobyteus/tools/browser/session_aware/shared_browser_session_manager.py +0 -25
  428. autobyteus/tools/browser/session_aware/web_element_action.py +0 -20
  429. autobyteus/tools/browser/standalone/__init__.py +0 -6
  430. autobyteus/tools/browser/standalone/factory/__init__.py +0 -0
  431. autobyteus/tools/browser/standalone/factory/webpage_reader_factory.py +0 -25
  432. autobyteus/tools/browser/standalone/factory/webpage_screenshot_taker_factory.py +0 -14
  433. autobyteus/tools/browser/standalone/navigate_to.py +0 -84
  434. autobyteus/tools/browser/standalone/web_page_pdf_generator.py +0 -101
  435. autobyteus/tools/browser/standalone/webpage_image_downloader.py +0 -169
  436. autobyteus/tools/browser/standalone/webpage_reader.py +0 -105
  437. autobyteus/tools/browser/standalone/webpage_screenshot_taker.py +0 -105
  438. autobyteus/tools/file/edit_file.py +0 -200
  439. autobyteus/tools/file/list_directory.py +0 -168
  440. autobyteus/tools/file/search_files.py +0 -188
  441. autobyteus/tools/timer.py +0 -175
  442. autobyteus/tools/usage/parsers/__init__.py +0 -22
  443. autobyteus/tools/usage/parsers/_json_extractor.py +0 -99
  444. autobyteus/tools/usage/parsers/_string_decoders.py +0 -18
  445. autobyteus/tools/usage/parsers/anthropic_xml_tool_usage_parser.py +0 -10
  446. autobyteus/tools/usage/parsers/base_parser.py +0 -41
  447. autobyteus/tools/usage/parsers/default_json_tool_usage_parser.py +0 -83
  448. autobyteus/tools/usage/parsers/default_xml_tool_usage_parser.py +0 -316
  449. autobyteus/tools/usage/parsers/exceptions.py +0 -13
  450. autobyteus/tools/usage/parsers/gemini_json_tool_usage_parser.py +0 -77
  451. autobyteus/tools/usage/parsers/openai_json_tool_usage_parser.py +0 -149
  452. autobyteus/tools/usage/parsers/provider_aware_tool_usage_parser.py +0 -59
  453. autobyteus/tools/usage/registries/tool_usage_parser_registry.py +0 -62
  454. autobyteus/workflow/phases/__init__.py +0 -11
  455. autobyteus/workflow/phases/workflow_operational_phase.py +0 -19
  456. autobyteus/workflow/phases/workflow_phase_manager.py +0 -48
  457. autobyteus-1.2.1.dist-info/METADATA +0 -205
  458. autobyteus-1.2.1.dist-info/RECORD +0 -511
  459. examples/__init__.py +0 -1
  460. examples/agent_team/__init__.py +0 -1
  461. examples/discover_phase_transitions.py +0 -104
  462. examples/run_agentic_software_engineer.py +0 -239
  463. examples/run_browser_agent.py +0 -262
  464. examples/run_google_slides_agent.py +0 -287
  465. examples/run_mcp_browser_client.py +0 -174
  466. examples/run_mcp_google_slides_client.py +0 -270
  467. examples/run_mcp_list_tools.py +0 -189
  468. examples/run_poem_writer.py +0 -284
  469. examples/run_sqlite_agent.py +0 -295
  470. /autobyteus/{tools/browser/session_aware → skills}/__init__.py +0 -0
  471. /autobyteus/tools/{browser/session_aware/factory → skill}/__init__.py +0 -0
  472. {autobyteus-1.2.1.dist-info → autobyteus-1.3.0.dist-info}/licenses/LICENSE +0 -0
@@ -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
 
@@ -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,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,13 +78,16 @@ 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
93
  return "generate_speech"
@@ -69,7 +96,7 @@ class GenerateSpeechTool(BaseTool):
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
136
  logger.info(f"generate_speech 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()
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
@@ -28,9 +28,10 @@ class DownloadMediaTool(BaseTool):
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
@@ -63,7 +64,20 @@ class DownloadMediaTool(BaseTool):
63
64
  # Security: prevent path traversal attacks.
64
65
  if ".." in folder:
65
66
  raise ValueError("Security error: 'folder' path cannot contain '..'.")
66
- destination_dir = os.path.abspath(folder)
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