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