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
@@ -6,7 +6,6 @@ from autobyteus.agent.handlers.base_event_handler import AgentEventHandler
6
6
  from autobyteus.agent.events import LLMCompleteResponseReceivedEvent
7
7
  from autobyteus.llm.utils.response_types import CompleteResponse
8
8
  from autobyteus.agent.llm_response_processor import BaseLLMResponseProcessor
9
- from autobyteus.tools.usage.parsers.exceptions import ToolUsageParseException
10
9
 
11
10
 
12
11
  if TYPE_CHECKING:
@@ -49,8 +48,8 @@ class LLMCompleteResponseReceivedEventHandler(AgentEventHandler):
49
48
  any_processor_took_action = False
50
49
 
51
50
  notifier: Optional['AgentExternalEventNotifier'] = None
52
- if context.phase_manager:
53
- notifier = context.phase_manager.notifier
51
+ if context.status_manager:
52
+ notifier = context.status_manager.notifier
54
53
 
55
54
  if not notifier: # pragma: no cover
56
55
  logger.error(f"Agent '{agent_id}': Notifier not available in LLMCompleteResponseReceivedEventHandler. Cannot emit complete response event.")
@@ -63,8 +62,15 @@ class LLMCompleteResponseReceivedEventHandler(AgentEventHandler):
63
62
  f"Proceeding to treat LLM response as output for this leg."
64
63
  )
65
64
  else:
65
+ valid_processors = []
66
+ for p in processor_instances_to_try:
67
+ if isinstance(p, BaseLLMResponseProcessor):
68
+ valid_processors.append(p)
69
+ else:
70
+ logger.error(f"Agent '{agent_id}': Invalid LLM response processor type in config: {type(p)}. Skipping.")
71
+
66
72
  # Sort processors by their order attribute
67
- sorted_processors = sorted(processor_instances_to_try, key=lambda p: p.get_order())
73
+ sorted_processors = sorted(valid_processors, key=lambda p: p.get_order())
68
74
  processor_names = [p.get_name() for p in sorted_processors]
69
75
  logger.debug(f"Agent '{agent_id}': Attempting LLM response processing in order: {processor_names}")
70
76
 
@@ -94,17 +100,6 @@ class LLMCompleteResponseReceivedEventHandler(AgentEventHandler):
94
100
  else:
95
101
  logger.debug(f"Agent '{agent_id}': LLMResponseProcessor '{processor_name_for_log}' did not handle the response.")
96
102
 
97
- except ToolUsageParseException as e_parse:
98
- # This is the key change: Catch the specific parsing exception
99
- logger.warning(f"Agent '{agent_id}': LLMResponseProcessor '{processor_name_for_log}' failed to parse tool usage: {e_parse}")
100
- if notifier:
101
- notifier.notify_agent_error_output_generation(
102
- error_source=f"LLMResponseProcessor.{processor_name_for_log}",
103
- error_message="The model's response contained a malformed tool call that could not be understood.",
104
- error_details=str(e_parse)
105
- )
106
- # A parsing failure should not prevent other processors from running.
107
-
108
103
  except Exception as e: # pragma: no cover
109
104
  logger.error(f"Agent '{agent_id}': Error while using LLMResponseProcessor '{processor_name_for_log}': {e}. This processor is skipped.", exc_info=True)
110
105
  if notifier:
@@ -1,13 +1,21 @@
1
1
  # file: autobyteus/autobyteus/agent/handlers/llm_user_message_ready_event_handler.py
2
2
  import logging
3
3
  import traceback
4
- from typing import TYPE_CHECKING, cast, Optional, List
4
+ import uuid
5
+ from typing import TYPE_CHECKING, Optional, List
5
6
 
6
7
  from autobyteus.agent.handlers.base_event_handler import AgentEventHandler
7
- from autobyteus.agent.events import LLMUserMessageReadyEvent, LLMCompleteResponseReceivedEvent
8
+ from autobyteus.agent.events import LLMUserMessageReadyEvent, LLMCompleteResponseReceivedEvent, PendingToolInvocationEvent
8
9
  from autobyteus.llm.user_message import LLMUserMessage
9
10
  from autobyteus.llm.utils.response_types import ChunkResponse, CompleteResponse
10
11
  from autobyteus.llm.utils.token_usage import TokenUsage
12
+ from autobyteus.agent.streaming.streaming_response_handler import StreamingResponseHandler
13
+ from autobyteus.agent.streaming.streaming_handler_factory import StreamingResponseHandlerFactory
14
+ from autobyteus.agent.streaming.parser.events import SegmentEvent, SegmentType
15
+ from autobyteus.agent.tool_invocation import ToolInvocationTurn
16
+ from autobyteus.agent.llm_request_assembler import LLMRequestAssembler
17
+ from autobyteus.agent.token_budget import apply_compaction_policy, resolve_token_budget
18
+ from autobyteus.llm.prompt_renderers.openai_chat_renderer import OpenAIChatRenderer
11
19
 
12
20
  if TYPE_CHECKING:
13
21
  from autobyteus.agent.context import AgentContext
@@ -18,9 +26,8 @@ logger = logging.getLogger(__name__)
18
26
  class LLMUserMessageReadyEventHandler(AgentEventHandler):
19
27
  """
20
28
  Handles LLMUserMessageReadyEvents by sending the prepared LLMUserMessage
21
- to the LLM, emitting AGENT_DATA_ASSISTANT_CHUNK events via the notifier
22
- for each chunk, emitting AGENT_DATA_ASSISTANT_CHUNK_STREAM_END upon completion,
23
- and then enqueuing an LLMCompleteResponseReceivedEvent with the full aggregated response.
29
+ to the LLM, passing the stream through StreamingResponseHandler for safe parsing,
30
+ emitting filtered chunks via the notifier, and finally enqueuing the complete response.
24
31
  """
25
32
 
26
33
  def __init__(self):
@@ -37,8 +44,8 @@ class LLMUserMessageReadyEventHandler(AgentEventHandler):
37
44
  if context.state.llm_instance is None:
38
45
  error_msg = f"Agent '{agent_id}' received LLMUserMessageReadyEvent but LLM instance is not yet initialized."
39
46
  logger.critical(error_msg)
40
- if context.phase_manager and context.phase_manager.notifier:
41
- context.phase_manager.notifier.notify_agent_error_output_generation( # USE RENAMED METHOD
47
+ if context.status_manager and context.status_manager.notifier:
48
+ context.status_manager.notifier.notify_agent_error_output_generation(
42
49
  error_source="LLMUserMessageReadyEventHandler.pre_llm_check",
43
50
  error_message=error_msg
44
51
  )
@@ -48,8 +55,13 @@ class LLMUserMessageReadyEventHandler(AgentEventHandler):
48
55
  logger.info(f"Agent '{agent_id}' handling LLMUserMessageReadyEvent: '{llm_user_message.content}'")
49
56
  logger.debug(f"Agent '{agent_id}' preparing to send full message to LLM:\n---\n{llm_user_message.content}\n---")
50
57
 
51
- context.state.add_message_to_history({"role": "user", "content": llm_user_message.content})
58
+ memory_manager = getattr(context.state, "memory_manager", None)
59
+ active_turn_id = getattr(context.state, "active_turn_id", None)
60
+ if memory_manager and not active_turn_id:
61
+ active_turn_id = memory_manager.start_turn()
62
+ context.state.active_turn_id = active_turn_id
52
63
 
64
+ # Initialize aggregators
53
65
  complete_response_text = ""
54
66
  complete_reasoning_text = ""
55
67
  token_usage: Optional[TokenUsage] = None
@@ -57,66 +69,192 @@ class LLMUserMessageReadyEventHandler(AgentEventHandler):
57
69
  complete_audio_urls: List[str] = []
58
70
  complete_video_urls: List[str] = []
59
71
 
72
+ # Get notifier for emitting events
60
73
  notifier: Optional['AgentExternalEventNotifier'] = None
61
- if context.phase_manager:
62
- notifier = context.phase_manager.notifier
74
+ if context.status_manager:
75
+ notifier = context.status_manager.notifier
63
76
 
64
77
  if not notifier: # pragma: no cover
65
78
  logger.error(f"Agent '{agent_id}': Notifier not available in LLMUserMessageReadyEventHandler. Cannot emit chunk events.")
66
79
 
80
+ # Callback for segment events from streaming parser
81
+ def emit_segment_event(event: SegmentEvent):
82
+ if notifier:
83
+ try:
84
+ notifier.notify_agent_segment_event(event.to_dict())
85
+ except Exception as e:
86
+ logger.error(f"Agent '{agent_id}': Error notifying segment event: {e}", exc_info=True)
87
+
88
+ # Collect tool names from agent state/config
89
+ tool_names: List[str] = []
90
+ if context.state.tool_instances:
91
+ tool_names = list(context.state.tool_instances.keys())
92
+ elif context.config.tools:
93
+ for tool in context.config.tools:
94
+ if isinstance(tool, str):
95
+ tool_names.append(tool)
96
+ elif hasattr(tool, "get_name"):
97
+ try:
98
+ tool_names.append(tool.get_name())
99
+ except Exception: # pragma: no cover - defensive
100
+ logger.warning(
101
+ "Agent '%s': Failed to resolve tool name from %s.",
102
+ agent_id,
103
+ type(tool),
104
+ )
105
+ else: # pragma: no cover - defensive
106
+ logger.warning(
107
+ "Agent '%s': Unsupported tool entry in config: %s.",
108
+ agent_id,
109
+ type(tool),
110
+ )
111
+
112
+ # Get provider from LLM instance
113
+ provider = context.state.llm_instance.model.provider if context.state.llm_instance else None
114
+
115
+ # Create streaming handler via factory (all configuration encapsulated)
116
+ handler_result = StreamingResponseHandlerFactory.create(
117
+ tool_names=tool_names,
118
+ provider=provider,
119
+ on_segment_event=emit_segment_event,
120
+ agent_id=agent_id,
121
+ )
122
+ streaming_handler = handler_result.handler
123
+
124
+ logger.info(
125
+ "Agent '%s': Streaming handler selected: %s",
126
+ agent_id,
127
+ streaming_handler.__class__.__name__,
128
+ )
129
+
130
+ # Prepare arguments for stream_user_message
131
+ stream_kwargs = {}
132
+ if handler_result.tool_schemas:
133
+ stream_kwargs["tools"] = handler_result.tool_schemas
134
+ logger.info(
135
+ "Agent '%s': Passing %d tool schemas to LLM API (Provider: %s)",
136
+ agent_id,
137
+ len(handler_result.tool_schemas),
138
+ provider,
139
+ )
140
+
141
+ if not memory_manager:
142
+ raise RuntimeError(f"Agent '{agent_id}' requires a memory manager to assemble LLM requests.")
143
+
144
+ llm_config = getattr(context.state.llm_instance, "config", None)
145
+ llm_model = getattr(context.state.llm_instance, "model", None)
146
+
147
+ renderer = getattr(context.state.llm_instance, "_renderer", None) or OpenAIChatRenderer()
148
+ assembler = LLMRequestAssembler(
149
+ memory_manager=memory_manager,
150
+ renderer=renderer,
151
+ )
152
+ system_prompt = (
153
+ context.state.processed_system_prompt
154
+ or context.state.llm_instance.config.system_message
155
+ )
156
+ request = await assembler.prepare_request(
157
+ processed_user_input=llm_user_message,
158
+ current_turn_id=active_turn_id,
159
+ system_prompt=system_prompt,
160
+ )
161
+
162
+ # State for manual reasoning parts (since they might come from outside the parser)
163
+ segment_id_prefix = f"turn_{uuid.uuid4().hex}:"
164
+ current_reasoning_part_id = None
165
+
67
166
  try:
68
- async for chunk_response in context.state.llm_instance.stream_user_message(llm_user_message):
167
+ async for chunk_response in context.state.llm_instance.stream_messages(
168
+ request.messages,
169
+ rendered_payload=request.rendered_payload,
170
+ **stream_kwargs,
171
+ ):
69
172
  if not isinstance(chunk_response, ChunkResponse):
70
173
  logger.warning(f"Agent '{agent_id}' received unexpected chunk type: {type(chunk_response)} during LLM stream. Expected ChunkResponse.")
71
174
  continue
72
175
 
176
+ # Aggregate full raw content
73
177
  if chunk_response.content:
74
178
  complete_response_text += chunk_response.content
75
179
  if chunk_response.reasoning:
76
180
  complete_reasoning_text += chunk_response.reasoning
77
181
 
182
+ # Collect usage and media from final chunks
78
183
  if chunk_response.is_complete:
79
184
  if chunk_response.usage:
80
185
  token_usage = chunk_response.usage
81
186
  logger.debug(f"Agent '{agent_id}' received final chunk with token usage: {token_usage}")
82
187
  if chunk_response.image_urls:
83
188
  complete_image_urls.extend(chunk_response.image_urls)
84
- logger.debug(f"Agent '{agent_id}' received final chunk with {len(chunk_response.image_urls)} image URLs.")
85
189
  if chunk_response.audio_urls:
86
190
  complete_audio_urls.extend(chunk_response.audio_urls)
87
- logger.debug(f"Agent '{agent_id}' received final chunk with {len(chunk_response.audio_urls)} audio URLs.")
88
191
  if chunk_response.video_urls:
89
192
  complete_video_urls.extend(chunk_response.video_urls)
90
- logger.debug(f"Agent '{agent_id}' received final chunk with {len(chunk_response.video_urls)} video URLs.")
91
193
 
92
- if notifier:
93
- try:
94
- # The chunk object now contains both content and reasoning
95
- notifier.notify_agent_data_assistant_chunk(chunk_response)
96
- except Exception as e_notify:
97
- logger.error(f"Agent '{agent_id}': Error notifying assistant chunk generated: {e_notify}", exc_info=True)
98
-
99
- if notifier:
100
- try:
101
- notifier.notify_agent_data_assistant_chunk_stream_end()
102
- except Exception as e_notify_end:
103
- logger.error(f"Agent '{agent_id}': Error notifying assistant chunk stream end: {e_notify_end}", exc_info=True)
194
+ # Handle Reasoning (Manual Segment Management)
195
+ if chunk_response.reasoning:
196
+ if current_reasoning_part_id is None:
197
+ current_reasoning_part_id = f"{segment_id_prefix}reasoning_{uuid.uuid4().hex}"
198
+ # Emit SEGMENT_START for reasoning
199
+ start_event = SegmentEvent.start(
200
+ segment_id=current_reasoning_part_id,
201
+ segment_type=SegmentType.REASONING
202
+ )
203
+ emit_segment_event(start_event)
204
+
205
+ # Emit SEGMENT_CONTENT for reasoning delta
206
+ content_event = SegmentEvent.content(
207
+ segment_id=current_reasoning_part_id,
208
+ delta=chunk_response.reasoning
209
+ )
210
+ emit_segment_event(content_event)
104
211
 
105
- logger.debug(f"Agent '{agent_id}' LLM stream completed. Full response length: {len(complete_response_text)}. Reasoning length: {len(complete_reasoning_text)}. Chunk stream ended event emitted.")
106
- if complete_reasoning_text:
107
- logger.debug(f"Agent '{agent_id}' aggregated full LLM reasoning:\n---\n{complete_reasoning_text}\n---")
108
- logger.debug(f"Agent '{agent_id}' aggregated full LLM response:\n---\n{complete_response_text}\n---")
212
+ # Handle Content & Tool Calls (Through Handler)
213
+ # Pass the full ChunkResponse object to support both text and tool call streams
214
+ streaming_handler.feed(chunk_response)
215
+
216
+ # End of stream loop
109
217
 
218
+ # Finalize the stream parser to get any held-back content
219
+ streaming_handler.finalize()
220
+
221
+ # After finalization, enqueue any parsed tool invocations.
222
+ if tool_names:
223
+ tool_invocations = streaming_handler.get_all_invocations()
224
+ if tool_invocations:
225
+ context.state.active_multi_tool_call_turn = ToolInvocationTurn(
226
+ invocations=tool_invocations
227
+ )
228
+ logger.info(
229
+ "Agent '%s': Parsed %d tool invocations from streaming parser.",
230
+ agent_id,
231
+ len(tool_invocations),
232
+ )
233
+ for invocation in tool_invocations:
234
+ if active_turn_id and not invocation.turn_id:
235
+ invocation.turn_id = active_turn_id
236
+ if memory_manager:
237
+ memory_manager.ingest_tool_intent(invocation, turn_id=active_turn_id)
238
+ await context.input_event_queues.enqueue_tool_invocation_request(
239
+ PendingToolInvocationEvent(tool_invocation=invocation)
240
+ )
241
+
242
+ # Close any open reasoning segment
243
+ if current_reasoning_part_id:
244
+ end_event = SegmentEvent.end(segment_id=current_reasoning_part_id)
245
+ emit_segment_event(end_event)
246
+
247
+ logger.debug(f"Agent '{agent_id}' LLM stream completed. Full response length: {len(complete_response_text)}.")
248
+ if complete_reasoning_text:
249
+ logger.debug(f"Agent '{agent_id}' aggregated full LLM reasoning.")
250
+
110
251
  except Exception as e:
111
252
  logger.error(f"Agent '{agent_id}' error during LLM stream: {e}", exc_info=True)
112
253
  error_message_for_output = f"Error processing your request with the LLM: {str(e)}"
113
254
 
114
255
  logger.warning(f"Agent '{agent_id}' LLM stream error. Error message for output: {error_message_for_output}")
115
- context.state.add_message_to_history({"role": "assistant", "content": error_message_for_output, "is_error": True})
116
-
117
256
  if notifier:
118
257
  try:
119
- notifier.notify_agent_data_assistant_chunk_stream_end()
120
258
  notifier.notify_agent_error_output_generation(
121
259
  error_source="LLMUserMessageReadyEventHandler.stream_user_message",
122
260
  error_message=error_message_for_output,
@@ -131,22 +269,10 @@ class LLMUserMessageReadyEventHandler(AgentEventHandler):
131
269
  is_error=True
132
270
  )
133
271
  await context.input_event_queues.enqueue_internal_system_event(llm_complete_event_on_error)
134
- logger.info(f"Agent '{agent_id}' enqueued LLMCompleteResponseReceivedEvent with error details from LLMUserMessageReadyEventHandler.")
272
+ logger.info(f"Agent '{agent_id}' enqueued LLMCompleteResponseReceivedEvent with error details.")
135
273
  return
136
274
 
137
- # Add message to history with reasoning and multimodal data
138
- history_entry = {"role": "assistant", "content": complete_response_text}
139
- if complete_reasoning_text:
140
- history_entry["reasoning"] = complete_reasoning_text
141
- if complete_image_urls:
142
- history_entry["image_urls"] = complete_image_urls
143
- if complete_audio_urls:
144
- history_entry["audio_urls"] = complete_audio_urls
145
- if complete_video_urls:
146
- history_entry["video_urls"] = complete_video_urls
147
- context.state.add_message_to_history(history_entry)
148
-
149
- # Create complete response with reasoning and multimodal data
275
+ # Create complete response
150
276
  complete_response_obj = CompleteResponse(
151
277
  content=complete_response_text,
152
278
  reasoning=complete_reasoning_text,
@@ -155,9 +281,23 @@ class LLMUserMessageReadyEventHandler(AgentEventHandler):
155
281
  audio_urls=complete_audio_urls,
156
282
  video_urls=complete_video_urls
157
283
  )
284
+ if memory_manager and active_turn_id:
285
+ memory_manager.ingest_assistant_response(
286
+ complete_response_obj,
287
+ turn_id=active_turn_id,
288
+ source_event="LLMCompleteResponseReceivedEvent",
289
+ )
290
+ if token_usage and llm_config and llm_model:
291
+ budget = resolve_token_budget(llm_model, llm_config, memory_manager.compaction_policy)
292
+ if budget:
293
+ apply_compaction_policy(memory_manager.compaction_policy, budget)
294
+ if memory_manager.compactor and memory_manager.compaction_policy.should_compact(
295
+ token_usage.prompt_tokens,
296
+ budget.input_budget,
297
+ ):
298
+ memory_manager.request_compaction()
158
299
  llm_complete_event = LLMCompleteResponseReceivedEvent(
159
300
  complete_response=complete_response_obj
160
301
  )
161
302
  await context.input_event_queues.enqueue_internal_system_event(llm_complete_event)
162
303
  logger.info(f"Agent '{agent_id}' enqueued LLMCompleteResponseReceivedEvent from LLMUserMessageReadyEventHandler.")
163
-
@@ -62,16 +62,6 @@ class ToolExecutionApprovalEventHandler(AgentEventHandler):
62
62
  )
63
63
 
64
64
  denial_reason_str = event.reason or "No specific reason provided."
65
- denial_content_for_history = f"Tool execution denied by user/system. Reason: {denial_reason_str}"
66
-
67
- context.state.add_message_to_history({
68
- "role": "tool",
69
- "tool_call_id": event.tool_invocation_id,
70
- "name": retrieved_invocation.name,
71
- "content": denial_content_for_history,
72
- })
73
- logger.debug(f"Agent '{context.agent_id}': Added 'tool' role denial message to history for '{retrieved_invocation.name}' (ID: {event.tool_invocation_id}).")
74
-
75
65
  prompt_content_for_llm = (
76
66
  f"The request to use the tool '{retrieved_invocation.name}' "
77
67
  f"(with arguments: {json.dumps(retrieved_invocation.arguments or {})}) was denied. "
@@ -1,12 +1,12 @@
1
1
  # file: autobyteus/autobyteus/agent/handlers/tool_invocation_request_event_handler.py
2
2
  import logging
3
- import json
4
3
  import traceback
5
4
  from typing import TYPE_CHECKING, Optional
6
5
 
7
6
  from autobyteus.agent.handlers.base_event_handler import AgentEventHandler
8
7
  from autobyteus.agent.events import PendingToolInvocationEvent, ToolResultEvent
9
8
  from autobyteus.agent.tool_invocation import ToolInvocation
9
+ from autobyteus.utils.llm_output_formatter import format_to_clean_string
10
10
 
11
11
  if TYPE_CHECKING:
12
12
  from autobyteus.agent.context import AgentContext
@@ -46,10 +46,35 @@ class ToolInvocationRequestEventHandler(AgentEventHandler):
46
46
  except Exception as e_notify:
47
47
  logger.error(f"Agent '{agent_id}': Error notifying tool auto-execution: {e_notify}", exc_info=True)
48
48
 
49
+ # Run tool invocation preprocessors (if any) before execution
50
+ processors = context.config.tool_invocation_preprocessors
51
+ if processors:
52
+ # Filter valid processors first to avoid sorting crashes (checking for get_order attribute)
53
+ valid_processors = [p for p in processors if hasattr(p, 'get_order')]
54
+ sorted_processors = sorted(valid_processors, key=lambda p: p.get_order())
55
+ for processor in sorted_processors:
56
+ try:
57
+ tool_invocation = await processor.process(tool_invocation, context)
58
+ tool_name = tool_invocation.name
59
+ arguments = tool_invocation.arguments
60
+ invocation_id = tool_invocation.id
61
+ except Exception as e:
62
+ error_message = f"Error in tool invocation preprocessor '{processor.get_name()}' for tool '{tool_name}': {e}"
63
+ logger.error(f"Agent '{agent_id}': {error_message}", exc_info=True)
64
+ result_event = ToolResultEvent(
65
+ tool_name=tool_name,
66
+ result=None,
67
+ error=error_message,
68
+ tool_invocation_id=invocation_id,
69
+ turn_id=tool_invocation.turn_id,
70
+ )
71
+ await context.input_event_queues.enqueue_tool_result(result_event)
72
+ return
73
+
49
74
  logger.info(f"Agent '{agent_id}' executing tool directly: '{tool_name}' (ID: {invocation_id}) with args: {arguments}")
50
75
 
51
76
  try:
52
- args_str = json.dumps(arguments)
77
+ args_str = format_to_clean_string(arguments)
53
78
  except TypeError:
54
79
  args_str = str(arguments)
55
80
 
@@ -71,13 +96,13 @@ class ToolInvocationRequestEventHandler(AgentEventHandler):
71
96
  if not tool_instance:
72
97
  error_message = f"Tool '{tool_name}' not found or configured for agent '{agent_id}'."
73
98
  logger.error(error_message)
74
- result_event = ToolResultEvent(tool_name=tool_name, result=None, error=error_message, tool_invocation_id=invocation_id)
75
- context.add_message_to_history({
76
- "role": "tool",
77
- "tool_call_id": invocation_id,
78
- "name": tool_name,
79
- "content": f"Error: Tool '{tool_name}' execution failed. Reason: {error_message}",
80
- })
99
+ result_event = ToolResultEvent(
100
+ tool_name=tool_name,
101
+ result=None,
102
+ error=error_message,
103
+ tool_invocation_id=invocation_id,
104
+ turn_id=tool_invocation.turn_id,
105
+ )
81
106
  log_msg_error = f"[TOOL_ERROR_DIRECT] {error_message}"
82
107
  if notifier:
83
108
  try:
@@ -97,20 +122,19 @@ class ToolInvocationRequestEventHandler(AgentEventHandler):
97
122
  execution_result = await tool_instance.execute(context=context, **arguments)
98
123
 
99
124
  try:
100
- result_json_for_log = json.dumps(execution_result)
125
+ result_json_for_log = format_to_clean_string(execution_result)
101
126
  except (TypeError, ValueError):
102
- result_json_for_log = json.dumps(str(execution_result))
127
+ result_json_for_log = format_to_clean_string(str(execution_result))
103
128
 
104
129
  logger.info(f"Tool '{tool_name}' (ID: {invocation_id}) executed by agent '{agent_id}'.")
105
- result_event = ToolResultEvent(tool_name=tool_name, result=execution_result, error=None, tool_invocation_id=invocation_id)
106
-
107
- history_content = str(execution_result)
108
- context.add_message_to_history({
109
- "role": "tool",
110
- "tool_call_id": invocation_id,
111
- "name": tool_name,
112
- "content": history_content,
113
- })
130
+ result_event = ToolResultEvent(
131
+ tool_name=tool_name,
132
+ result=execution_result,
133
+ error=None,
134
+ tool_invocation_id=invocation_id,
135
+ tool_args=arguments,
136
+ turn_id=tool_invocation.turn_id,
137
+ )
114
138
  log_msg_result = f"[TOOL_RESULT_DIRECT] {result_json_for_log}"
115
139
  if notifier:
116
140
  try:
@@ -124,13 +148,13 @@ class ToolInvocationRequestEventHandler(AgentEventHandler):
124
148
  error_message = f"Error executing tool '{tool_name}' (ID: {invocation_id}): {str(e)}"
125
149
  error_details = traceback.format_exc()
126
150
  logger.error(f"Agent '{agent_id}' {error_message}", exc_info=True)
127
- result_event = ToolResultEvent(tool_name=tool_name, result=None, error=error_message, tool_invocation_id=invocation_id)
128
- context.add_message_to_history({
129
- "role": "tool",
130
- "tool_call_id": invocation_id,
131
- "name": tool_name,
132
- "content": f"Error: Tool '{tool_name}' execution failed. Reason: {error_message}",
133
- })
151
+ result_event = ToolResultEvent(
152
+ tool_name=tool_name,
153
+ result=None,
154
+ error=error_message,
155
+ tool_invocation_id=invocation_id,
156
+ turn_id=tool_invocation.turn_id,
157
+ )
134
158
  log_msg_exception = f"[TOOL_EXCEPTION_DIRECT] {error_message}\nDetails:\n{error_details}"
135
159
  if notifier:
136
160
  try:
@@ -161,8 +185,8 @@ class ToolInvocationRequestEventHandler(AgentEventHandler):
161
185
  agent_id = context.agent_id
162
186
 
163
187
  notifier: Optional['AgentExternalEventNotifier'] = None
164
- if context.phase_manager:
165
- notifier = context.phase_manager.notifier
188
+ if context.status_manager:
189
+ notifier = context.status_manager.notifier
166
190
 
167
191
  if not notifier:
168
192
  logger.error(f"Agent '{agent_id}': Notifier not available in ToolInvocationRequestEventHandler. Output events for tool approval/logging will be lost.")
@@ -175,25 +199,6 @@ class ToolInvocationRequestEventHandler(AgentEventHandler):
175
199
 
176
200
  context.store_pending_tool_invocation(tool_invocation)
177
201
 
178
- try:
179
- arguments_json_str = json.dumps(tool_invocation.arguments or {})
180
- except TypeError:
181
- logger.warning(f"Could not serialize args for history tool_call for '{tool_invocation.name}'. Using empty dict string.")
182
- arguments_json_str = "{}"
183
-
184
- context.add_message_to_history({
185
- "role": "assistant",
186
- "content": None,
187
- "tool_calls": [{
188
- "id": tool_invocation.id,
189
- "type": "function",
190
- "function": {
191
- "name": tool_invocation.name,
192
- "arguments": arguments_json_str
193
- }
194
- }]
195
- })
196
-
197
202
  approval_data = {
198
203
  "invocation_id": tool_invocation.id,
199
204
  "tool_name": tool_invocation.name,
@@ -1,6 +1,6 @@
1
1
  # file: autobyteus/autobyteus/agent/handlers/tool_result_event_handler.py
2
2
  import logging
3
- import json
3
+
4
4
  from typing import TYPE_CHECKING, Optional, List
5
5
 
6
6
  from autobyteus.agent.handlers.base_event_handler import AgentEventHandler
@@ -9,6 +9,7 @@ from autobyteus.agent.tool_execution_result_processor import BaseToolExecutionRe
9
9
  from autobyteus.agent.message.context_file import ContextFile
10
10
  from autobyteus.agent.message import AgentInputUserMessage
11
11
  from autobyteus.agent.sender_type import SenderType
12
+ from autobyteus.utils.llm_output_formatter import format_to_clean_string
12
13
 
13
14
  if TYPE_CHECKING:
14
15
  from autobyteus.agent.context import AgentContext
@@ -81,10 +82,7 @@ class ToolResultEventHandler(AgentEventHandler):
81
82
  aggregated_content_parts.append(content_part)
82
83
  # Handle standard text/JSON results
83
84
  else:
84
- try:
85
- result_str = json.dumps(p_event.result, indent=2) if not isinstance(p_event.result, str) else p_event.result
86
- except TypeError: # pragma: no cover
87
- result_str = str(p_event.result)
85
+ result_str = format_to_clean_string(p_event.result)
88
86
  content_part = (
89
87
  f"Tool: {p_event.tool_name} (ID: {tool_invocation_id})\n"
90
88
  f"Status: Success\n"
@@ -120,7 +118,7 @@ class ToolResultEventHandler(AgentEventHandler):
120
118
  return
121
119
 
122
120
  agent_id = context.agent_id
123
- notifier: Optional['AgentExternalEventNotifier'] = context.phase_manager.notifier if context.phase_manager else None
121
+ notifier: Optional['AgentExternalEventNotifier'] = context.status_manager.notifier if context.status_manager else None
124
122
 
125
123
  # --- Step 1: Immediately process the incoming event ---
126
124
  processed_event = event
@@ -144,7 +142,7 @@ class ToolResultEventHandler(AgentEventHandler):
144
142
  if processed_event.error:
145
143
  log_message = f"[TOOL_RESULT_ERROR_PROCESSED] Agent_ID: {agent_id}, Tool: {processed_event.tool_name}, Invocation_ID: {tool_invocation_id}, Error: {processed_event.error}"
146
144
  else:
147
- log_message = f"[TOOL_RESULT_SUCCESS_PROCESSED] Agent_ID: {agent_id}, Tool: {processed_event.tool_name}, Invocation_ID: {tool_invocation_id}, Result: {str(processed_event.result)}"
145
+ log_message = f"[TOOL_RESULT_SUCCESS_PROCESSED] Agent_ID: {agent_id}, Tool: {processed_event.tool_name}, Invocation_ID: {tool_invocation_id}, Result: {format_to_clean_string(processed_event.result)}"
148
146
 
149
147
  try:
150
148
  log_data = {
@@ -195,7 +193,8 @@ class ToolResultEventHandler(AgentEventHandler):
195
193
  tool_name=original_invocation.name,
196
194
  result=None,
197
195
  error=f"Critical Error: Result for this tool call was lost.",
198
- tool_invocation_id=original_invocation.id
196
+ tool_invocation_id=original_invocation.id,
197
+ turn_id=original_invocation.turn_id,
199
198
  ))
200
199
 
201
200
  await self._dispatch_results_to_input_pipeline(sorted_results, context)
@@ -39,8 +39,8 @@ class UserInputMessageEventHandler(AgentEventHandler):
39
39
 
40
40
  # --- UPDATED LOGIC: Check sender_type for system-generated tasks and notify TUI ---
41
41
  if original_agent_input_user_msg.sender_type == SenderType.SYSTEM:
42
- if context.phase_manager:
43
- notifier: 'AgentExternalEventNotifier' = context.phase_manager.notifier
42
+ if context.status_manager:
43
+ notifier: 'AgentExternalEventNotifier' = context.status_manager.notifier
44
44
  notification_data = {
45
45
  "sender_id": original_agent_input_user_msg.metadata.get("sender_id", "system"),
46
46
  "content": original_agent_input_user_msg.content,
@@ -59,8 +59,15 @@ class UserInputMessageEventHandler(AgentEventHandler):
59
59
 
60
60
  processor_instances = context.config.input_processors
61
61
  if processor_instances:
62
+ valid_processors = []
63
+ for p in processor_instances:
64
+ if isinstance(p, BaseAgentUserInputMessageProcessor):
65
+ valid_processors.append(p)
66
+ else:
67
+ logger.error(f"Agent '{context.agent_id}': Invalid input processor type in config: {type(p)}. Skipping.")
68
+
62
69
  # Sort processors by their order attribute
63
- sorted_processors = sorted(processor_instances, key=lambda p: p.get_order())
70
+ sorted_processors = sorted(valid_processors, key=lambda p: p.get_order())
64
71
  processor_names = [p.get_name() for p in sorted_processors]
65
72
  logger.debug(f"Agent '{context.agent_id}': Applying input processors in order: {processor_names}")
66
73