autobyteus 1.2.0__py3-none-any.whl → 1.2.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (512) hide show
  1. autobyteus/agent/agent.py +15 -5
  2. autobyteus/agent/bootstrap_steps/__init__.py +1 -3
  3. autobyteus/agent/bootstrap_steps/agent_bootstrapper.py +3 -59
  4. autobyteus/agent/bootstrap_steps/base_bootstrap_step.py +1 -4
  5. autobyteus/agent/bootstrap_steps/mcp_server_prewarming_step.py +1 -3
  6. autobyteus/agent/bootstrap_steps/system_prompt_processing_step.py +16 -13
  7. autobyteus/agent/bootstrap_steps/workspace_context_initialization_step.py +2 -4
  8. autobyteus/agent/context/agent_config.py +43 -20
  9. autobyteus/agent/context/agent_context.py +23 -18
  10. autobyteus/agent/context/agent_runtime_state.py +23 -19
  11. autobyteus/agent/events/__init__.py +16 -1
  12. autobyteus/agent/events/agent_events.py +43 -3
  13. autobyteus/agent/events/agent_input_event_queue_manager.py +79 -26
  14. autobyteus/agent/events/event_store.py +57 -0
  15. autobyteus/agent/events/notifiers.py +74 -60
  16. autobyteus/agent/events/worker_event_dispatcher.py +21 -64
  17. autobyteus/agent/factory/agent_factory.py +52 -0
  18. autobyteus/agent/handlers/__init__.py +2 -0
  19. autobyteus/agent/handlers/approved_tool_invocation_event_handler.py +51 -34
  20. autobyteus/agent/handlers/bootstrap_event_handler.py +155 -0
  21. autobyteus/agent/handlers/inter_agent_message_event_handler.py +10 -0
  22. autobyteus/agent/handlers/lifecycle_event_logger.py +19 -11
  23. autobyteus/agent/handlers/llm_complete_response_received_event_handler.py +10 -15
  24. autobyteus/agent/handlers/llm_user_message_ready_event_handler.py +188 -48
  25. autobyteus/agent/handlers/tool_execution_approval_event_handler.py +0 -10
  26. autobyteus/agent/handlers/tool_invocation_request_event_handler.py +53 -48
  27. autobyteus/agent/handlers/tool_result_event_handler.py +7 -8
  28. autobyteus/agent/handlers/user_input_message_event_handler.py +10 -3
  29. autobyteus/agent/input_processor/memory_ingest_input_processor.py +40 -0
  30. autobyteus/agent/lifecycle/__init__.py +12 -0
  31. autobyteus/agent/lifecycle/base_processor.py +109 -0
  32. autobyteus/agent/lifecycle/events.py +35 -0
  33. autobyteus/agent/lifecycle/processor_definition.py +36 -0
  34. autobyteus/agent/lifecycle/processor_registry.py +106 -0
  35. autobyteus/agent/llm_request_assembler.py +98 -0
  36. autobyteus/agent/llm_response_processor/__init__.py +1 -8
  37. autobyteus/agent/message/context_file_type.py +1 -1
  38. autobyteus/agent/message/send_message_to.py +5 -4
  39. autobyteus/agent/runtime/agent_runtime.py +29 -21
  40. autobyteus/agent/runtime/agent_worker.py +98 -19
  41. autobyteus/agent/shutdown_steps/__init__.py +2 -0
  42. autobyteus/agent/shutdown_steps/agent_shutdown_orchestrator.py +2 -0
  43. autobyteus/agent/shutdown_steps/tool_cleanup_step.py +58 -0
  44. autobyteus/agent/status/__init__.py +14 -0
  45. autobyteus/agent/status/manager.py +93 -0
  46. autobyteus/agent/status/status_deriver.py +96 -0
  47. autobyteus/agent/{phases/phase_enum.py → status/status_enum.py} +16 -16
  48. autobyteus/agent/status/status_update_utils.py +73 -0
  49. autobyteus/agent/streaming/__init__.py +52 -5
  50. autobyteus/agent/streaming/adapters/__init__.py +18 -0
  51. autobyteus/agent/streaming/adapters/invocation_adapter.py +184 -0
  52. autobyteus/agent/streaming/adapters/tool_call_parsing.py +163 -0
  53. autobyteus/agent/streaming/adapters/tool_syntax_registry.py +67 -0
  54. autobyteus/agent/streaming/agent_event_stream.py +3 -178
  55. autobyteus/agent/streaming/api_tool_call/__init__.py +16 -0
  56. autobyteus/agent/streaming/api_tool_call/file_content_streamer.py +56 -0
  57. autobyteus/agent/streaming/api_tool_call/json_string_field_extractor.py +175 -0
  58. autobyteus/agent/streaming/api_tool_call_streaming_response_handler.py +4 -0
  59. autobyteus/agent/streaming/events/__init__.py +6 -0
  60. autobyteus/agent/streaming/events/stream_event_payloads.py +284 -0
  61. autobyteus/agent/streaming/events/stream_events.py +141 -0
  62. autobyteus/agent/streaming/handlers/__init__.py +15 -0
  63. autobyteus/agent/streaming/handlers/api_tool_call_streaming_response_handler.py +303 -0
  64. autobyteus/agent/streaming/handlers/parsing_streaming_response_handler.py +107 -0
  65. autobyteus/agent/streaming/handlers/pass_through_streaming_response_handler.py +107 -0
  66. autobyteus/agent/streaming/handlers/streaming_handler_factory.py +177 -0
  67. autobyteus/agent/streaming/handlers/streaming_response_handler.py +58 -0
  68. autobyteus/agent/streaming/parser/__init__.py +61 -0
  69. autobyteus/agent/streaming/parser/event_emitter.py +181 -0
  70. autobyteus/agent/streaming/parser/events.py +4 -0
  71. autobyteus/agent/streaming/parser/invocation_adapter.py +4 -0
  72. autobyteus/agent/streaming/parser/json_parsing_strategies/__init__.py +19 -0
  73. autobyteus/agent/streaming/parser/json_parsing_strategies/base.py +32 -0
  74. autobyteus/agent/streaming/parser/json_parsing_strategies/default.py +34 -0
  75. autobyteus/agent/streaming/parser/json_parsing_strategies/gemini.py +31 -0
  76. autobyteus/agent/streaming/parser/json_parsing_strategies/openai.py +64 -0
  77. autobyteus/agent/streaming/parser/json_parsing_strategies/registry.py +75 -0
  78. autobyteus/agent/streaming/parser/parser_context.py +227 -0
  79. autobyteus/agent/streaming/parser/parser_factory.py +132 -0
  80. autobyteus/agent/streaming/parser/sentinel_format.py +7 -0
  81. autobyteus/agent/streaming/parser/state_factory.py +62 -0
  82. autobyteus/agent/streaming/parser/states/__init__.py +1 -0
  83. autobyteus/agent/streaming/parser/states/base_state.py +60 -0
  84. autobyteus/agent/streaming/parser/states/custom_xml_tag_run_bash_parsing_state.py +38 -0
  85. autobyteus/agent/streaming/parser/states/custom_xml_tag_write_file_parsing_state.py +55 -0
  86. autobyteus/agent/streaming/parser/states/delimited_content_state.py +146 -0
  87. autobyteus/agent/streaming/parser/states/json_initialization_state.py +144 -0
  88. autobyteus/agent/streaming/parser/states/json_tool_parsing_state.py +137 -0
  89. autobyteus/agent/streaming/parser/states/sentinel_content_state.py +30 -0
  90. autobyteus/agent/streaming/parser/states/sentinel_initialization_state.py +117 -0
  91. autobyteus/agent/streaming/parser/states/text_state.py +78 -0
  92. autobyteus/agent/streaming/parser/states/xml_patch_file_tool_parsing_state.py +328 -0
  93. autobyteus/agent/streaming/parser/states/xml_run_bash_tool_parsing_state.py +129 -0
  94. autobyteus/agent/streaming/parser/states/xml_tag_initialization_state.py +151 -0
  95. autobyteus/agent/streaming/parser/states/xml_tool_parsing_state.py +63 -0
  96. autobyteus/agent/streaming/parser/states/xml_write_file_tool_parsing_state.py +343 -0
  97. autobyteus/agent/streaming/parser/strategies/__init__.py +17 -0
  98. autobyteus/agent/streaming/parser/strategies/base.py +24 -0
  99. autobyteus/agent/streaming/parser/strategies/json_tool_strategy.py +26 -0
  100. autobyteus/agent/streaming/parser/strategies/registry.py +28 -0
  101. autobyteus/agent/streaming/parser/strategies/sentinel_strategy.py +23 -0
  102. autobyteus/agent/streaming/parser/strategies/xml_tag_strategy.py +21 -0
  103. autobyteus/agent/streaming/parser/stream_scanner.py +167 -0
  104. autobyteus/agent/streaming/parser/streaming_parser.py +212 -0
  105. autobyteus/agent/streaming/parser/tool_call_parsing.py +4 -0
  106. autobyteus/agent/streaming/parser/tool_constants.py +7 -0
  107. autobyteus/agent/streaming/parser/tool_syntax_registry.py +4 -0
  108. autobyteus/agent/streaming/parser/xml_tool_parsing_state_registry.py +55 -0
  109. autobyteus/agent/streaming/parsing_streaming_response_handler.py +4 -0
  110. autobyteus/agent/streaming/pass_through_streaming_response_handler.py +4 -0
  111. autobyteus/agent/streaming/queue_streamer.py +3 -57
  112. autobyteus/agent/streaming/segments/__init__.py +5 -0
  113. autobyteus/agent/streaming/segments/segment_events.py +81 -0
  114. autobyteus/agent/streaming/stream_event_payloads.py +2 -198
  115. autobyteus/agent/streaming/stream_events.py +3 -128
  116. autobyteus/agent/streaming/streaming_handler_factory.py +4 -0
  117. autobyteus/agent/streaming/streaming_response_handler.py +4 -0
  118. autobyteus/agent/streaming/streams/__init__.py +5 -0
  119. autobyteus/agent/streaming/streams/agent_event_stream.py +197 -0
  120. autobyteus/agent/streaming/utils/__init__.py +5 -0
  121. autobyteus/agent/streaming/utils/queue_streamer.py +59 -0
  122. autobyteus/agent/system_prompt_processor/__init__.py +2 -0
  123. autobyteus/agent/system_prompt_processor/available_skills_processor.py +96 -0
  124. autobyteus/agent/system_prompt_processor/base_processor.py +1 -1
  125. autobyteus/agent/system_prompt_processor/processor_meta.py +15 -2
  126. autobyteus/agent/system_prompt_processor/tool_manifest_injector_processor.py +39 -58
  127. autobyteus/agent/token_budget.py +56 -0
  128. autobyteus/agent/tool_execution_result_processor/memory_ingest_tool_result_processor.py +29 -0
  129. autobyteus/agent/tool_invocation.py +16 -40
  130. autobyteus/agent/tool_invocation_preprocessor/__init__.py +9 -0
  131. autobyteus/agent/tool_invocation_preprocessor/base_preprocessor.py +45 -0
  132. autobyteus/agent/tool_invocation_preprocessor/processor_definition.py +15 -0
  133. autobyteus/agent/tool_invocation_preprocessor/processor_meta.py +33 -0
  134. autobyteus/agent/tool_invocation_preprocessor/processor_registry.py +60 -0
  135. autobyteus/agent/utils/wait_for_idle.py +12 -14
  136. autobyteus/agent/workspace/base_workspace.py +6 -27
  137. autobyteus/agent_team/agent_team.py +3 -3
  138. autobyteus/agent_team/agent_team_builder.py +1 -41
  139. autobyteus/agent_team/bootstrap_steps/__init__.py +0 -4
  140. autobyteus/agent_team/bootstrap_steps/agent_configuration_preparation_step.py +8 -18
  141. autobyteus/agent_team/bootstrap_steps/agent_team_bootstrapper.py +4 -16
  142. autobyteus/agent_team/bootstrap_steps/base_agent_team_bootstrap_step.py +1 -2
  143. autobyteus/agent_team/bootstrap_steps/coordinator_initialization_step.py +1 -2
  144. autobyteus/agent_team/bootstrap_steps/task_notifier_initialization_step.py +5 -6
  145. autobyteus/agent_team/bootstrap_steps/team_context_initialization_step.py +15 -15
  146. autobyteus/agent_team/context/agent_team_config.py +6 -3
  147. autobyteus/agent_team/context/agent_team_context.py +25 -3
  148. autobyteus/agent_team/context/agent_team_runtime_state.py +11 -8
  149. autobyteus/agent_team/events/__init__.py +11 -0
  150. autobyteus/agent_team/events/agent_team_event_dispatcher.py +22 -9
  151. autobyteus/agent_team/events/agent_team_events.py +16 -0
  152. autobyteus/agent_team/events/event_store.py +57 -0
  153. autobyteus/agent_team/factory/agent_team_factory.py +8 -0
  154. autobyteus/agent_team/handlers/inter_agent_message_request_event_handler.py +18 -2
  155. autobyteus/agent_team/handlers/lifecycle_agent_team_event_handler.py +21 -5
  156. autobyteus/agent_team/handlers/process_user_message_event_handler.py +17 -8
  157. autobyteus/agent_team/handlers/tool_approval_team_event_handler.py +19 -4
  158. autobyteus/agent_team/runtime/agent_team_runtime.py +41 -10
  159. autobyteus/agent_team/runtime/agent_team_worker.py +69 -5
  160. autobyteus/agent_team/status/__init__.py +14 -0
  161. autobyteus/agent_team/status/agent_team_status.py +18 -0
  162. autobyteus/agent_team/status/agent_team_status_manager.py +33 -0
  163. autobyteus/agent_team/status/status_deriver.py +62 -0
  164. autobyteus/agent_team/status/status_update_utils.py +42 -0
  165. autobyteus/agent_team/streaming/__init__.py +2 -2
  166. autobyteus/agent_team/streaming/agent_team_event_notifier.py +10 -10
  167. autobyteus/agent_team/streaming/agent_team_stream_event_payloads.py +7 -7
  168. autobyteus/agent_team/streaming/agent_team_stream_events.py +11 -11
  169. autobyteus/agent_team/system_prompt_processor/__init__.py +6 -0
  170. autobyteus/agent_team/system_prompt_processor/team_manifest_injector_processor.py +76 -0
  171. autobyteus/agent_team/task_notification/activation_policy.py +1 -1
  172. autobyteus/agent_team/task_notification/system_event_driven_agent_task_notifier.py +22 -22
  173. autobyteus/agent_team/task_notification/task_notification_mode.py +20 -1
  174. autobyteus/agent_team/utils/wait_for_idle.py +4 -4
  175. autobyteus/cli/agent_cli.py +18 -10
  176. autobyteus/cli/agent_team_tui/app.py +18 -15
  177. autobyteus/cli/agent_team_tui/state.py +21 -23
  178. autobyteus/cli/agent_team_tui/widgets/agent_list_sidebar.py +15 -15
  179. autobyteus/cli/agent_team_tui/widgets/focus_pane.py +146 -39
  180. autobyteus/cli/agent_team_tui/widgets/renderables.py +1 -1
  181. autobyteus/cli/agent_team_tui/widgets/shared.py +26 -26
  182. autobyteus/cli/agent_team_tui/widgets/{task_board_panel.py → task_plan_panel.py} +5 -5
  183. autobyteus/cli/cli_display.py +193 -44
  184. autobyteus/cli/workflow_tui/app.py +9 -10
  185. autobyteus/cli/workflow_tui/state.py +14 -16
  186. autobyteus/cli/workflow_tui/widgets/agent_list_sidebar.py +15 -15
  187. autobyteus/cli/workflow_tui/widgets/focus_pane.py +137 -35
  188. autobyteus/cli/workflow_tui/widgets/renderables.py +1 -1
  189. autobyteus/cli/workflow_tui/widgets/shared.py +25 -25
  190. autobyteus/clients/autobyteus_client.py +94 -1
  191. autobyteus/events/event_types.py +15 -21
  192. autobyteus/llm/api/autobyteus_llm.py +33 -29
  193. autobyteus/llm/api/claude_llm.py +142 -36
  194. autobyteus/llm/api/gemini_llm.py +163 -59
  195. autobyteus/llm/api/grok_llm.py +1 -1
  196. autobyteus/llm/api/minimax_llm.py +26 -0
  197. autobyteus/llm/api/mistral_llm.py +113 -87
  198. autobyteus/llm/api/ollama_llm.py +9 -42
  199. autobyteus/llm/api/openai_compatible_llm.py +127 -91
  200. autobyteus/llm/api/openai_llm.py +3 -3
  201. autobyteus/llm/api/openai_responses_llm.py +324 -0
  202. autobyteus/llm/api/zhipu_llm.py +21 -2
  203. autobyteus/llm/autobyteus_provider.py +70 -60
  204. autobyteus/llm/base_llm.py +85 -81
  205. autobyteus/llm/converters/__init__.py +14 -0
  206. autobyteus/llm/converters/anthropic_tool_call_converter.py +37 -0
  207. autobyteus/llm/converters/gemini_tool_call_converter.py +57 -0
  208. autobyteus/llm/converters/mistral_tool_call_converter.py +37 -0
  209. autobyteus/llm/converters/openai_tool_call_converter.py +38 -0
  210. autobyteus/llm/extensions/base_extension.py +6 -12
  211. autobyteus/llm/extensions/token_usage_tracking_extension.py +45 -18
  212. autobyteus/llm/llm_factory.py +282 -204
  213. autobyteus/llm/lmstudio_provider.py +60 -49
  214. autobyteus/llm/models.py +35 -2
  215. autobyteus/llm/ollama_provider.py +60 -49
  216. autobyteus/llm/ollama_provider_resolver.py +0 -1
  217. autobyteus/llm/prompt_renderers/__init__.py +19 -0
  218. autobyteus/llm/prompt_renderers/anthropic_prompt_renderer.py +104 -0
  219. autobyteus/llm/prompt_renderers/autobyteus_prompt_renderer.py +19 -0
  220. autobyteus/llm/prompt_renderers/base_prompt_renderer.py +10 -0
  221. autobyteus/llm/prompt_renderers/gemini_prompt_renderer.py +63 -0
  222. autobyteus/llm/prompt_renderers/mistral_prompt_renderer.py +87 -0
  223. autobyteus/llm/prompt_renderers/ollama_prompt_renderer.py +51 -0
  224. autobyteus/llm/prompt_renderers/openai_chat_renderer.py +97 -0
  225. autobyteus/llm/prompt_renderers/openai_responses_renderer.py +101 -0
  226. autobyteus/llm/providers.py +1 -3
  227. autobyteus/llm/token_counter/claude_token_counter.py +56 -25
  228. autobyteus/llm/token_counter/mistral_token_counter.py +12 -8
  229. autobyteus/llm/token_counter/openai_token_counter.py +24 -5
  230. autobyteus/llm/token_counter/token_counter_factory.py +12 -5
  231. autobyteus/llm/utils/llm_config.py +6 -12
  232. autobyteus/llm/utils/media_payload_formatter.py +27 -20
  233. autobyteus/llm/utils/messages.py +55 -3
  234. autobyteus/llm/utils/response_types.py +3 -0
  235. autobyteus/llm/utils/tool_call_delta.py +31 -0
  236. autobyteus/memory/__init__.py +32 -0
  237. autobyteus/memory/active_transcript.py +69 -0
  238. autobyteus/memory/compaction/__init__.py +9 -0
  239. autobyteus/memory/compaction/compaction_result.py +8 -0
  240. autobyteus/memory/compaction/compactor.py +89 -0
  241. autobyteus/memory/compaction/summarizer.py +11 -0
  242. autobyteus/memory/compaction_snapshot_builder.py +84 -0
  243. autobyteus/memory/memory_manager.py +183 -0
  244. autobyteus/memory/models/__init__.py +14 -0
  245. autobyteus/memory/models/episodic_item.py +41 -0
  246. autobyteus/memory/models/memory_types.py +7 -0
  247. autobyteus/memory/models/raw_trace_item.py +79 -0
  248. autobyteus/memory/models/semantic_item.py +41 -0
  249. autobyteus/memory/models/tool_interaction.py +20 -0
  250. autobyteus/memory/policies/__init__.py +5 -0
  251. autobyteus/memory/policies/compaction_policy.py +16 -0
  252. autobyteus/memory/retrieval/__init__.py +7 -0
  253. autobyteus/memory/retrieval/memory_bundle.py +11 -0
  254. autobyteus/memory/retrieval/retriever.py +13 -0
  255. autobyteus/memory/store/__init__.py +7 -0
  256. autobyteus/memory/store/base_store.py +14 -0
  257. autobyteus/memory/store/file_store.py +98 -0
  258. autobyteus/memory/tool_interaction_builder.py +46 -0
  259. autobyteus/memory/turn_tracker.py +9 -0
  260. autobyteus/multimedia/audio/api/__init__.py +3 -2
  261. autobyteus/multimedia/audio/api/autobyteus_audio_client.py +19 -5
  262. autobyteus/multimedia/audio/api/gemini_audio_client.py +108 -16
  263. autobyteus/multimedia/audio/api/openai_audio_client.py +112 -0
  264. autobyteus/multimedia/audio/audio_client_factory.py +84 -9
  265. autobyteus/multimedia/audio/audio_model.py +2 -1
  266. autobyteus/multimedia/image/api/autobyteus_image_client.py +19 -5
  267. autobyteus/multimedia/image/api/gemini_image_client.py +38 -17
  268. autobyteus/multimedia/image/api/openai_image_client.py +125 -43
  269. autobyteus/multimedia/image/autobyteus_image_provider.py +2 -1
  270. autobyteus/multimedia/image/image_client_factory.py +47 -15
  271. autobyteus/multimedia/image/image_model.py +5 -2
  272. autobyteus/multimedia/providers.py +3 -2
  273. autobyteus/skills/loader.py +71 -0
  274. autobyteus/skills/model.py +11 -0
  275. autobyteus/skills/registry.py +70 -0
  276. autobyteus/task_management/__init__.py +43 -20
  277. autobyteus/task_management/{base_task_board.py → base_task_plan.py} +16 -13
  278. autobyteus/task_management/converters/__init__.py +2 -2
  279. autobyteus/task_management/converters/{task_board_converter.py → task_plan_converter.py} +13 -13
  280. autobyteus/task_management/events.py +7 -7
  281. autobyteus/task_management/{in_memory_task_board.py → in_memory_task_plan.py} +34 -22
  282. autobyteus/task_management/schemas/__init__.py +3 -0
  283. autobyteus/task_management/schemas/task_status_report.py +2 -2
  284. autobyteus/task_management/schemas/todo_definition.py +15 -0
  285. autobyteus/task_management/todo.py +29 -0
  286. autobyteus/task_management/todo_list.py +75 -0
  287. autobyteus/task_management/tools/__init__.py +24 -8
  288. autobyteus/task_management/tools/task_tools/__init__.py +19 -0
  289. autobyteus/task_management/tools/{assign_task_to.py → task_tools/assign_task_to.py} +18 -18
  290. autobyteus/task_management/tools/{publish_task.py → task_tools/create_task.py} +16 -18
  291. autobyteus/task_management/tools/{publish_tasks.py → task_tools/create_tasks.py} +19 -19
  292. autobyteus/task_management/tools/{get_my_tasks.py → task_tools/get_my_tasks.py} +15 -15
  293. autobyteus/task_management/tools/{get_task_board_status.py → task_tools/get_task_plan_status.py} +16 -16
  294. autobyteus/task_management/tools/{update_task_status.py → task_tools/update_task_status.py} +16 -16
  295. autobyteus/task_management/tools/todo_tools/__init__.py +18 -0
  296. autobyteus/task_management/tools/todo_tools/add_todo.py +78 -0
  297. autobyteus/task_management/tools/todo_tools/create_todo_list.py +79 -0
  298. autobyteus/task_management/tools/todo_tools/get_todo_list.py +55 -0
  299. autobyteus/task_management/tools/todo_tools/update_todo_status.py +85 -0
  300. autobyteus/tools/__init__.py +43 -52
  301. autobyteus/tools/base_tool.py +7 -0
  302. autobyteus/tools/file/__init__.py +9 -0
  303. autobyteus/tools/file/patch_file.py +149 -0
  304. autobyteus/tools/file/{file_reader.py → read_file.py} +38 -7
  305. autobyteus/tools/file/{file_writer.py → write_file.py} +7 -4
  306. autobyteus/tools/functional_tool.py +53 -14
  307. autobyteus/tools/mcp/__init__.py +2 -0
  308. autobyteus/tools/mcp/config_service.py +5 -1
  309. autobyteus/tools/mcp/server/__init__.py +2 -0
  310. autobyteus/tools/mcp/server/http_managed_mcp_server.py +1 -1
  311. autobyteus/tools/mcp/server/websocket_managed_mcp_server.py +141 -0
  312. autobyteus/tools/mcp/server_instance_manager.py +8 -1
  313. autobyteus/tools/mcp/tool.py +3 -3
  314. autobyteus/tools/mcp/tool_registrar.py +5 -2
  315. autobyteus/tools/mcp/types.py +61 -0
  316. autobyteus/tools/multimedia/__init__.py +2 -1
  317. autobyteus/tools/multimedia/audio_tools.py +72 -19
  318. autobyteus/tools/{download_media_tool.py → multimedia/download_media_tool.py} +21 -7
  319. autobyteus/tools/multimedia/image_tools.py +248 -64
  320. autobyteus/tools/multimedia/media_reader_tool.py +1 -1
  321. autobyteus/tools/operation_executor/journal_manager.py +107 -0
  322. autobyteus/tools/operation_executor/operation_event_buffer.py +57 -0
  323. autobyteus/tools/operation_executor/operation_event_producer.py +29 -0
  324. autobyteus/tools/operation_executor/operation_executor.py +58 -0
  325. autobyteus/tools/registry/tool_definition.py +108 -14
  326. autobyteus/tools/registry/tool_registry.py +29 -0
  327. autobyteus/tools/search/__init__.py +17 -0
  328. autobyteus/tools/search/base_strategy.py +35 -0
  329. autobyteus/tools/search/client.py +24 -0
  330. autobyteus/tools/search/factory.py +81 -0
  331. autobyteus/tools/search/google_cse_strategy.py +68 -0
  332. autobyteus/tools/search/providers.py +10 -0
  333. autobyteus/tools/search/serpapi_strategy.py +65 -0
  334. autobyteus/tools/search/serper_strategy.py +87 -0
  335. autobyteus/tools/search_tool.py +83 -0
  336. autobyteus/tools/skill/load_skill.py +50 -0
  337. autobyteus/tools/terminal/__init__.py +45 -0
  338. autobyteus/tools/terminal/ansi_utils.py +32 -0
  339. autobyteus/tools/terminal/background_process_manager.py +233 -0
  340. autobyteus/tools/terminal/output_buffer.py +105 -0
  341. autobyteus/tools/terminal/prompt_detector.py +63 -0
  342. autobyteus/tools/terminal/pty_session.py +241 -0
  343. autobyteus/tools/terminal/session_factory.py +20 -0
  344. autobyteus/tools/terminal/terminal_session_manager.py +226 -0
  345. autobyteus/tools/terminal/tools/__init__.py +13 -0
  346. autobyteus/tools/terminal/tools/get_process_output.py +81 -0
  347. autobyteus/tools/terminal/tools/run_bash.py +109 -0
  348. autobyteus/tools/terminal/tools/start_background_process.py +104 -0
  349. autobyteus/tools/terminal/tools/stop_background_process.py +67 -0
  350. autobyteus/tools/terminal/types.py +54 -0
  351. autobyteus/tools/terminal/wsl_tmux_session.py +221 -0
  352. autobyteus/tools/terminal/wsl_utils.py +156 -0
  353. autobyteus/tools/tool_meta.py +4 -24
  354. autobyteus/tools/transaction_management/backup_handler.py +48 -0
  355. autobyteus/tools/transaction_management/operation_lifecycle_manager.py +62 -0
  356. autobyteus/tools/usage/__init__.py +1 -2
  357. autobyteus/tools/usage/formatters/__init__.py +17 -1
  358. autobyteus/tools/usage/formatters/base_formatter.py +8 -0
  359. autobyteus/tools/usage/formatters/default_xml_schema_formatter.py +2 -2
  360. autobyteus/tools/usage/formatters/mistral_json_schema_formatter.py +18 -0
  361. autobyteus/tools/usage/formatters/patch_file_xml_example_formatter.py +64 -0
  362. autobyteus/tools/usage/formatters/patch_file_xml_schema_formatter.py +31 -0
  363. autobyteus/tools/usage/formatters/run_bash_xml_example_formatter.py +32 -0
  364. autobyteus/tools/usage/formatters/run_bash_xml_schema_formatter.py +36 -0
  365. autobyteus/tools/usage/formatters/write_file_xml_example_formatter.py +53 -0
  366. autobyteus/tools/usage/formatters/write_file_xml_schema_formatter.py +31 -0
  367. autobyteus/tools/usage/providers/tool_manifest_provider.py +10 -10
  368. autobyteus/tools/usage/registries/__init__.py +1 -3
  369. autobyteus/tools/usage/registries/tool_formatting_registry.py +115 -8
  370. autobyteus/tools/usage/tool_schema_provider.py +51 -0
  371. autobyteus/tools/web/__init__.py +4 -0
  372. autobyteus/tools/web/read_url_tool.py +80 -0
  373. autobyteus/utils/diff_utils.py +271 -0
  374. autobyteus/utils/download_utils.py +109 -0
  375. autobyteus/utils/file_utils.py +57 -2
  376. autobyteus/utils/gemini_helper.py +56 -0
  377. autobyteus/utils/gemini_model_mapping.py +71 -0
  378. autobyteus/utils/llm_output_formatter.py +75 -0
  379. autobyteus/utils/tool_call_format.py +36 -0
  380. autobyteus/workflow/agentic_workflow.py +3 -3
  381. autobyteus/workflow/bootstrap_steps/agent_tool_injection_step.py +2 -2
  382. autobyteus/workflow/bootstrap_steps/base_workflow_bootstrap_step.py +2 -2
  383. autobyteus/workflow/bootstrap_steps/coordinator_initialization_step.py +2 -2
  384. autobyteus/workflow/bootstrap_steps/coordinator_prompt_preparation_step.py +4 -11
  385. autobyteus/workflow/bootstrap_steps/workflow_bootstrapper.py +6 -6
  386. autobyteus/workflow/bootstrap_steps/workflow_runtime_queue_initialization_step.py +2 -2
  387. autobyteus/workflow/context/workflow_context.py +3 -3
  388. autobyteus/workflow/context/workflow_runtime_state.py +5 -5
  389. autobyteus/workflow/events/workflow_event_dispatcher.py +5 -5
  390. autobyteus/workflow/handlers/lifecycle_workflow_event_handler.py +3 -3
  391. autobyteus/workflow/handlers/process_user_message_event_handler.py +5 -5
  392. autobyteus/workflow/handlers/tool_approval_workflow_event_handler.py +2 -2
  393. autobyteus/workflow/runtime/workflow_runtime.py +8 -8
  394. autobyteus/workflow/runtime/workflow_worker.py +3 -3
  395. autobyteus/workflow/status/__init__.py +11 -0
  396. autobyteus/workflow/status/workflow_status.py +19 -0
  397. autobyteus/workflow/status/workflow_status_manager.py +48 -0
  398. autobyteus/workflow/streaming/__init__.py +2 -2
  399. autobyteus/workflow/streaming/workflow_event_notifier.py +7 -7
  400. autobyteus/workflow/streaming/workflow_stream_event_payloads.py +4 -4
  401. autobyteus/workflow/streaming/workflow_stream_events.py +3 -3
  402. autobyteus/workflow/utils/wait_for_idle.py +4 -4
  403. autobyteus-1.2.3.dist-info/METADATA +293 -0
  404. autobyteus-1.2.3.dist-info/RECORD +600 -0
  405. {autobyteus-1.2.0.dist-info → autobyteus-1.2.3.dist-info}/WHEEL +1 -1
  406. {autobyteus-1.2.0.dist-info → autobyteus-1.2.3.dist-info}/top_level.txt +0 -1
  407. autobyteus/agent/bootstrap_steps/agent_runtime_queue_initialization_step.py +0 -57
  408. autobyteus/agent/hooks/__init__.py +0 -16
  409. autobyteus/agent/hooks/base_phase_hook.py +0 -78
  410. autobyteus/agent/hooks/hook_definition.py +0 -36
  411. autobyteus/agent/hooks/hook_meta.py +0 -37
  412. autobyteus/agent/hooks/hook_registry.py +0 -106
  413. autobyteus/agent/llm_response_processor/provider_aware_tool_usage_processor.py +0 -103
  414. autobyteus/agent/phases/__init__.py +0 -18
  415. autobyteus/agent/phases/discover.py +0 -53
  416. autobyteus/agent/phases/manager.py +0 -265
  417. autobyteus/agent/phases/transition_decorator.py +0 -40
  418. autobyteus/agent/phases/transition_info.py +0 -33
  419. autobyteus/agent/remote_agent.py +0 -244
  420. autobyteus/agent/workspace/workspace_definition.py +0 -36
  421. autobyteus/agent/workspace/workspace_meta.py +0 -37
  422. autobyteus/agent/workspace/workspace_registry.py +0 -72
  423. autobyteus/agent_team/bootstrap_steps/agent_team_runtime_queue_initialization_step.py +0 -25
  424. autobyteus/agent_team/bootstrap_steps/coordinator_prompt_preparation_step.py +0 -85
  425. autobyteus/agent_team/phases/__init__.py +0 -11
  426. autobyteus/agent_team/phases/agent_team_operational_phase.py +0 -19
  427. autobyteus/agent_team/phases/agent_team_phase_manager.py +0 -48
  428. autobyteus/llm/api/bedrock_llm.py +0 -92
  429. autobyteus/llm/api/groq_llm.py +0 -94
  430. autobyteus/llm/api/nvidia_llm.py +0 -108
  431. autobyteus/llm/utils/token_pricing_config.py +0 -87
  432. autobyteus/person/examples/sample_persons.py +0 -14
  433. autobyteus/person/examples/sample_roles.py +0 -14
  434. autobyteus/person/person.py +0 -29
  435. autobyteus/person/role.py +0 -14
  436. autobyteus/rpc/__init__.py +0 -73
  437. autobyteus/rpc/client/__init__.py +0 -17
  438. autobyteus/rpc/client/abstract_client_connection.py +0 -124
  439. autobyteus/rpc/client/client_connection_manager.py +0 -153
  440. autobyteus/rpc/client/sse_client_connection.py +0 -306
  441. autobyteus/rpc/client/stdio_client_connection.py +0 -280
  442. autobyteus/rpc/config/__init__.py +0 -13
  443. autobyteus/rpc/config/agent_server_config.py +0 -153
  444. autobyteus/rpc/config/agent_server_registry.py +0 -152
  445. autobyteus/rpc/hosting.py +0 -244
  446. autobyteus/rpc/protocol.py +0 -244
  447. autobyteus/rpc/server/__init__.py +0 -20
  448. autobyteus/rpc/server/agent_server_endpoint.py +0 -181
  449. autobyteus/rpc/server/base_method_handler.py +0 -40
  450. autobyteus/rpc/server/method_handlers.py +0 -259
  451. autobyteus/rpc/server/sse_server_handler.py +0 -182
  452. autobyteus/rpc/server/stdio_server_handler.py +0 -151
  453. autobyteus/rpc/server_main.py +0 -198
  454. autobyteus/rpc/transport_type.py +0 -13
  455. autobyteus/tools/bash/__init__.py +0 -2
  456. autobyteus/tools/bash/bash_executor.py +0 -100
  457. autobyteus/tools/browser/__init__.py +0 -2
  458. autobyteus/tools/browser/session_aware/__init__.py +0 -0
  459. autobyteus/tools/browser/session_aware/browser_session_aware_navigate_to.py +0 -75
  460. autobyteus/tools/browser/session_aware/browser_session_aware_tool.py +0 -30
  461. autobyteus/tools/browser/session_aware/browser_session_aware_web_element_trigger.py +0 -154
  462. autobyteus/tools/browser/session_aware/browser_session_aware_webpage_reader.py +0 -89
  463. autobyteus/tools/browser/session_aware/browser_session_aware_webpage_screenshot_taker.py +0 -107
  464. autobyteus/tools/browser/session_aware/factory/__init__.py +0 -0
  465. autobyteus/tools/browser/session_aware/factory/browser_session_aware_web_element_trigger_factory.py +0 -14
  466. autobyteus/tools/browser/session_aware/factory/browser_session_aware_webpage_reader_factory.py +0 -26
  467. autobyteus/tools/browser/session_aware/factory/browser_session_aware_webpage_screenshot_taker_factory.py +0 -14
  468. autobyteus/tools/browser/session_aware/shared_browser_session.py +0 -11
  469. autobyteus/tools/browser/session_aware/shared_browser_session_manager.py +0 -25
  470. autobyteus/tools/browser/session_aware/web_element_action.py +0 -20
  471. autobyteus/tools/browser/standalone/__init__.py +0 -6
  472. autobyteus/tools/browser/standalone/factory/__init__.py +0 -0
  473. autobyteus/tools/browser/standalone/factory/webpage_reader_factory.py +0 -25
  474. autobyteus/tools/browser/standalone/factory/webpage_screenshot_taker_factory.py +0 -14
  475. autobyteus/tools/browser/standalone/navigate_to.py +0 -80
  476. autobyteus/tools/browser/standalone/web_page_pdf_generator.py +0 -97
  477. autobyteus/tools/browser/standalone/webpage_image_downloader.py +0 -165
  478. autobyteus/tools/browser/standalone/webpage_reader.py +0 -101
  479. autobyteus/tools/browser/standalone/webpage_screenshot_taker.py +0 -101
  480. autobyteus/tools/file/file_editor.py +0 -200
  481. autobyteus/tools/google_search.py +0 -149
  482. autobyteus/tools/timer.py +0 -171
  483. autobyteus/tools/usage/parsers/__init__.py +0 -22
  484. autobyteus/tools/usage/parsers/_json_extractor.py +0 -99
  485. autobyteus/tools/usage/parsers/_string_decoders.py +0 -18
  486. autobyteus/tools/usage/parsers/anthropic_xml_tool_usage_parser.py +0 -10
  487. autobyteus/tools/usage/parsers/base_parser.py +0 -41
  488. autobyteus/tools/usage/parsers/default_json_tool_usage_parser.py +0 -83
  489. autobyteus/tools/usage/parsers/default_xml_tool_usage_parser.py +0 -316
  490. autobyteus/tools/usage/parsers/exceptions.py +0 -13
  491. autobyteus/tools/usage/parsers/gemini_json_tool_usage_parser.py +0 -77
  492. autobyteus/tools/usage/parsers/openai_json_tool_usage_parser.py +0 -149
  493. autobyteus/tools/usage/parsers/provider_aware_tool_usage_parser.py +0 -59
  494. autobyteus/tools/usage/registries/tool_usage_parser_registry.py +0 -62
  495. autobyteus/workflow/phases/__init__.py +0 -11
  496. autobyteus/workflow/phases/workflow_operational_phase.py +0 -19
  497. autobyteus/workflow/phases/workflow_phase_manager.py +0 -48
  498. autobyteus-1.2.0.dist-info/METADATA +0 -205
  499. autobyteus-1.2.0.dist-info/RECORD +0 -496
  500. examples/__init__.py +0 -1
  501. examples/agent_team/__init__.py +0 -1
  502. examples/discover_phase_transitions.py +0 -104
  503. examples/run_browser_agent.py +0 -262
  504. examples/run_google_slides_agent.py +0 -287
  505. examples/run_mcp_browser_client.py +0 -174
  506. examples/run_mcp_google_slides_client.py +0 -270
  507. examples/run_mcp_list_tools.py +0 -189
  508. examples/run_poem_writer.py +0 -284
  509. examples/run_sqlite_agent.py +0 -295
  510. /autobyteus/{person → skills}/__init__.py +0 -0
  511. /autobyteus/{person/examples → tools/skill}/__init__.py +0 -0
  512. {autobyteus-1.2.0.dist-info → autobyteus-1.2.3.dist-info}/licenses/LICENSE +0 -0
@@ -1,259 +0,0 @@
1
- # file: autobyteus/autobyteus/rpc/server/method_handlers.py
2
- import logging
3
- from typing import Optional, Dict, Any, List, Callable, Awaitable, Tuple
4
-
5
- from autobyteus.rpc.protocol import ProtocolMessage, MessageType, RequestType, ResponseType, ErrorCode
6
- from autobyteus.rpc.server.base_method_handler import BaseMethodHandler
7
- from autobyteus.agent.agent import Agent
8
- from autobyteus.agent.message.agent_input_user_message import AgentInputUserMessage
9
- from autobyteus.agent.message.inter_agent_message import InterAgentMessage
10
-
11
-
12
- logger = logging.getLogger(__name__)
13
-
14
- class DiscoverCapabilitiesHandler(BaseMethodHandler):
15
- """
16
- Handles the 'discover_capabilities' RPC method.
17
- Responds with the agent's ID, definition details, supported methods, and status,
18
- obtained via the Agent's public interface/context.
19
- """
20
- async def handle(self,
21
- request_id: Optional[str],
22
- params: Optional[Dict[str, Any]],
23
- agent: Agent) -> ProtocolMessage:
24
- logger.debug(f"DiscoverCapabilitiesHandler: Handling request_id '{request_id}' for agent '{agent.agent_id}'.")
25
- try:
26
- # Define capabilities, including the new stream download initiation method
27
- capabilities = {
28
- "post_user_message": {
29
- "description": "Posts a message from an external user to the agent.",
30
- "params": {"agent_input_user_message": "dict (serialized AgentInputUserMessage)"}
31
- },
32
- "post_inter_agent_message": {
33
- "description": "Posts a message from another agent.",
34
- "params": {"inter_agent_message": "dict (serialized InterAgentMessage)"}
35
- },
36
- "post_tool_execution_approval": {
37
- "description": "Provides approval or denial for a pending tool execution.",
38
- "params": {"tool_invocation_id": "str", "is_approved": "bool", "reason": "Optional[str]"}
39
- },
40
- "get_status": {
41
- "description": "Gets the current operational status of the agent.",
42
- "params": None
43
- },
44
- # No specific invoke method for REQUEST_STREAM_DOWNLOAD, it's a top-level RequestType handled by its own handler.
45
- # However, if it were invoked via InvokeMethod, it would be listed here.
46
- # For clarity, methods invokable via InvokeMethodHandler are listed.
47
- # REQUEST_STREAM_DOWNLOAD will be handled by InitiateStreamDownloadHandler directly.
48
- }
49
-
50
- if not agent.context:
51
- logger.error(f"Agent '{agent.agent_id}' context is None. Cannot discover capabilities.")
52
- return ProtocolMessage.create_error_response(
53
- id=request_id,
54
- code=ErrorCode.SERVER_ERROR_CAPABILITY_DISCOVERY_FAILED,
55
- message="Agent context not available."
56
- )
57
-
58
- # Explicitly list RequestTypes that this server (potentially) handles
59
- # This part of discover_capabilities might need to be more dynamic or list top-level RPC methods
60
- # rather than just methods invokable via InvokeMethodHandler.
61
- # For now, assume InvokeMethodHandler is the primary way to call agent functions.
62
- # The fact that REQUEST_STREAM_DOWNLOAD exists is a server capability.
63
- supported_rpc_request_types = [rt.value for rt in RequestType]
64
-
65
-
66
- result_data = {
67
- "agent_id": agent.agent_id,
68
- "agent_name": agent.context.definition.name,
69
- "agent_role": agent.context.definition.role,
70
- "agent_description": agent.context.definition.description,
71
- "supported_rpc_request_types": supported_rpc_request_types, # Top-level RPC methods
72
- "invokable_methods_details": capabilities, # Methods callable via 'invoke_method'
73
- "status": agent.get_status().value,
74
- "system_prompt_summary": agent.context.definition.system_prompt[:200] + "..." if len(agent.context.definition.system_prompt) > 200 else agent.context.definition.system_prompt,
75
- "tool_names": agent.context.definition.tool_names,
76
- }
77
- return ProtocolMessage.create_response(
78
- id=request_id,
79
- result=result_data,
80
- response_type=ResponseType.CAPABILITIES_RESPONSE
81
- )
82
- except Exception as e:
83
- logger.error(f"Error in DiscoverCapabilitiesHandler for agent '{agent.agent_id}': {e}", exc_info=True)
84
- return ProtocolMessage.create_error_response(
85
- id=request_id,
86
- code=ErrorCode.SERVER_ERROR_CAPABILITY_DISCOVERY_FAILED,
87
- message=f"Failed to discover capabilities: {e}"
88
- )
89
-
90
-
91
- class InvokeMethodHandler(BaseMethodHandler):
92
- """
93
- Handles the 'invoke_method' RPC method.
94
- It dispatches to public methods of the Agent instance based on 'method_name'.
95
- """
96
-
97
- def __init__(self):
98
- # Map method names to Agent's public API methods (or wrappers around them)
99
- self._method_map: Dict[str, Callable[[Optional[str], Dict[str, Any], Agent], Awaitable[ProtocolMessage]]] = {
100
- "post_user_message": self._handle_post_user_message,
101
- "post_inter_agent_message": self._handle_post_inter_agent_message,
102
- "post_tool_execution_approval": self._handle_post_tool_execution_approval,
103
- "get_status": self._handle_get_status,
104
- }
105
-
106
- async def handle(self,
107
- request_id: Optional[str],
108
- params: Optional[Dict[str, Any]],
109
- agent: Agent) -> ProtocolMessage:
110
- if not params or "method_name" not in params:
111
- return ProtocolMessage.create_error_response(
112
- id=request_id,
113
- code=ErrorCode.INVALID_PARAMS,
114
- message="'method_name' is required in params for invoke_method."
115
- )
116
-
117
- method_name = params["method_name"]
118
- method_params = params.get("method_params", {})
119
-
120
- logger.debug(f"InvokeMethodHandler: Handling method '{method_name}' for agent '{agent.agent_id}' with request_id '{request_id}'.")
121
-
122
- handler_func = self._method_map.get(method_name)
123
- if not handler_func:
124
- return ProtocolMessage.create_error_response(
125
- id=request_id,
126
- code=ErrorCode.METHOD_NOT_FOUND,
127
- message=f"Method '{method_name}' is not supported by this agent server for invocation via InvokeMethodHandler."
128
- )
129
-
130
- try:
131
- return await handler_func(request_id, method_params, agent)
132
- except Exception as e:
133
- logger.error(f"Error invoking method '{method_name}' on agent '{agent.agent_id}': {e}", exc_info=True)
134
- return ProtocolMessage.create_error_response(
135
- id=request_id,
136
- code=ErrorCode.SERVER_ERROR_AGENT_PROCESSING_FAILED,
137
- message=f"Error processing method '{method_name}': {e}"
138
- )
139
-
140
- async def _handle_post_user_message(self, request_id: Optional[str], params: Dict[str, Any], agent: Agent) -> ProtocolMessage:
141
- serialized_msg = params.get("agent_input_user_message")
142
- if not isinstance(serialized_msg, dict):
143
- return ProtocolMessage.create_error_response(request_id, ErrorCode.INVALID_PARAMS, "'agent_input_user_message' (dict) parameter is required.")
144
-
145
- try:
146
- user_message = AgentInputUserMessage.from_dict(serialized_msg)
147
- except (ValueError, TypeError) as e:
148
- return ProtocolMessage.create_error_response(request_id, ErrorCode.INVALID_PARAMS, f"Invalid 'agent_input_user_message' structure: {e}")
149
-
150
- await agent.post_user_message(user_message)
151
- logger.info(f"Agent '{agent.agent_id}' (via RPC): Called agent.post_user_message().")
152
- return ProtocolMessage.create_response(request_id, {"status": "User message posted to agent"}, ResponseType.ACKNOWLEDGEMENT)
153
-
154
- async def _handle_post_inter_agent_message(self, request_id: Optional[str], params: Dict[str, Any], agent: Agent) -> ProtocolMessage:
155
- serialized_msg = params.get("inter_agent_message")
156
- if not isinstance(serialized_msg, dict):
157
- return ProtocolMessage.create_error_response(request_id, ErrorCode.INVALID_PARAMS, "'inter_agent_message' (dict) parameter is required.")
158
-
159
- try:
160
- msg_type_str = serialized_msg.get("message_type")
161
- if not msg_type_str: raise ValueError("message_type missing")
162
-
163
- inter_agent_msg = InterAgentMessage.create_with_dynamic_message_type(
164
- recipient_role_name=serialized_msg.get("recipient_role_name"),
165
- recipient_agent_id=serialized_msg.get("recipient_agent_id"),
166
- content=serialized_msg.get("content"),
167
- message_type=msg_type_str,
168
- sender_agent_id=serialized_msg.get("sender_agent_id")
169
- )
170
- except (ValueError, TypeError) as e:
171
- return ProtocolMessage.create_error_response(request_id, ErrorCode.INVALID_PARAMS, f"Invalid 'inter_agent_message' structure: {e}")
172
-
173
- await agent.post_inter_agent_message(inter_agent_msg)
174
- logger.info(f"Agent '{agent.agent_id}' (via RPC): Called agent.post_inter_agent_message() from '{inter_agent_msg.sender_agent_id}'.")
175
- return ProtocolMessage.create_response(request_id, {"status": "Inter-agent message posted to agent"}, ResponseType.ACKNOWLEDGEMENT)
176
-
177
- async def _handle_post_tool_execution_approval(self, request_id: Optional[str], params: Dict[str, Any], agent: Agent) -> ProtocolMessage:
178
- tool_invocation_id = params.get("tool_invocation_id")
179
- is_approved = params.get("is_approved")
180
- reason = params.get("reason")
181
-
182
- if not isinstance(tool_invocation_id, str) or not tool_invocation_id:
183
- return ProtocolMessage.create_error_response(request_id, ErrorCode.INVALID_PARAMS, "'tool_invocation_id' (str) is required.")
184
- if not isinstance(is_approved, bool):
185
- return ProtocolMessage.create_error_response(request_id, ErrorCode.INVALID_PARAMS, "'is_approved' (bool) is required.")
186
- if reason is not None and not isinstance(reason, str):
187
- return ProtocolMessage.create_error_response(request_id, ErrorCode.INVALID_PARAMS, "'reason' must be a string if provided.")
188
-
189
- await agent.post_tool_execution_approval(tool_invocation_id, is_approved, reason)
190
- status_str = "approved" if is_approved else "denied"
191
- logger.info(f"Agent '{agent.agent_id}' (via RPC): Called agent.post_tool_execution_approval() for id '{tool_invocation_id}' ({status_str}).")
192
- return ProtocolMessage.create_response(request_id, {"status": f"Tool approval ({status_str}) posted to agent"}, ResponseType.ACKNOWLEDGEMENT)
193
-
194
- async def _handle_get_status(self, request_id: Optional[str], params: Dict[str, Any], agent: Agent) -> ProtocolMessage:
195
- status_value = agent.get_status().value
196
- logger.debug(f"Agent '{agent.agent_id}' (via RPC): Current status is '{status_value}'.")
197
- return ProtocolMessage.create_response(request_id, {"status": status_value, "agent_id": agent.agent_id})
198
-
199
-
200
- class InitiateStreamDownloadHandler(BaseMethodHandler):
201
- """
202
- Handles the 'request_stream_download' RPC method.
203
- Interacts with the agent to prepare a streamable resource and returns
204
- information required by the client to download it, including a stream_id.
205
- The SseServerHandler will augment this response with the full download URL.
206
- """
207
- async def handle(self,
208
- request_id: Optional[str],
209
- params: Optional[Dict[str, Any]],
210
- agent: Agent) -> ProtocolMessage:
211
- logger.debug(f"InitiateStreamDownloadHandler: Handling request_id '{request_id}' for agent '{agent.agent_id}' with params: {params}.")
212
- if not params:
213
- return ProtocolMessage.create_error_response(
214
- id=request_id,
215
- code=ErrorCode.INVALID_PARAMS,
216
- message="Parameters are required for requesting a stream download (e.g., resource identifier)."
217
- )
218
-
219
- try:
220
- # Agent must implement `prepare_resource_for_streaming`
221
- # This method is conceptual; actual signature might vary.
222
- # It should return (stream_id: str, metadata: Dict[str, Any])
223
- # The agent becomes responsible for managing the lifecycle of this stream_id
224
- # and providing data when get_stream_data(stream_id) is called by SseServerHandler.
225
- if not hasattr(agent, "prepare_resource_for_streaming"):
226
- logger.error(f"Agent '{agent.agent_id}' does not support 'prepare_resource_for_streaming'.")
227
- return ProtocolMessage.create_error_response(
228
- id=request_id,
229
- code=ErrorCode.METHOD_NOT_FOUND,
230
- message=f"Agent '{agent.agent_id}' cannot prepare streamable resources."
231
- )
232
-
233
- # Type hint for clarity if agent method is known
234
- # stream_id, metadata = await agent.prepare_resource_for_streaming(params)
235
- stream_preparation_result: Tuple[str, Dict[str, Any]] = await agent.prepare_resource_for_streaming(params)
236
- stream_id, metadata = stream_preparation_result
237
-
238
- logger.info(f"Agent '{agent.agent_id}' prepared stream_id '{stream_id}' for request_id '{request_id}'.")
239
-
240
- # The SseServerHandler will add the 'download_url' to this result later
241
- # agent_id_on_server is also added by SseServerHandler for constructing the URL
242
- result_payload = {
243
- "stream_id": stream_id,
244
- "metadata": metadata,
245
- # "agent_id_on_server": agent.agent_id # Or the server_key if different. SseServerHandler knows this.
246
- }
247
-
248
- return ProtocolMessage.create_response(
249
- id=request_id,
250
- result=result_payload,
251
- response_type=ResponseType.STREAM_DOWNLOAD_READY
252
- )
253
- except Exception as e:
254
- logger.error(f"Error in InitiateStreamDownloadHandler for agent '{agent.agent_id}': {e}", exc_info=True)
255
- return ProtocolMessage.create_error_response(
256
- id=request_id,
257
- code=ErrorCode.SERVER_ERROR_STREAM_PREPARATION_FAILED,
258
- message=f"Agent failed to prepare stream: {e}"
259
- )
@@ -1,182 +0,0 @@
1
- # file: autobyteus/autobyteus/rpc/server/sse_server_handler.py
2
- import asyncio
3
- import logging
4
- import json
5
- from typing import Dict, Optional, Union, Set, cast, AsyncIterator
6
- from weakref import WeakSet
7
-
8
- from aiohttp import web
9
- from aiohttp_sse import sse_response
10
-
11
- from autobyteus.agent.agent import Agent
12
- # MODIFIED: Import AgentEventStream (remains the same, but it's now the sole class)
13
- from autobyteus.agent.streaming import AgentEventStream
14
- from autobyteus.agent.streaming.stream_events import StreamEvent, StreamEventType
15
- from autobyteus.rpc.protocol import ProtocolMessage, MessageType, ErrorCode, RequestType, ResponseType, EventType as RPCEventType
16
- from autobyteus.rpc.server.base_method_handler import BaseMethodHandler
17
- from autobyteus.rpc.config import AgentServerConfig
18
-
19
- logger = logging.getLogger(__name__)
20
-
21
- DEFAULT_STREAM_CHUNK_SIZE = 8192
22
-
23
- class SseServerHandler:
24
- def __init__(self, agents: Dict[str, Agent], method_handlers: Dict[Union[RequestType, str], BaseMethodHandler]):
25
- self._agents: Dict[str, Agent] = agents
26
- self._method_handlers = method_handlers
27
- self._app = web.Application()
28
- self._runner: Optional[web.AppRunner] = None
29
- self._site: Optional[web.TCPSite] = None
30
- self._active_sse_forwarding_tasks: Dict[web.StreamResponse, asyncio.Task] = {}
31
- logger.info(f"SseServerHandler initialized to serve agents: {list(self._agents.keys())}.")
32
-
33
- def _setup_routes(self, config: AgentServerConfig):
34
- # ... (method body remains the same) ...
35
- rpc_request_path = config.sse_request_endpoint
36
- base_events_path = config.sse_events_endpoint.rstrip('/')
37
- full_events_path = f"{base_events_path}/{{agent_id_on_server}}"
38
- stream_download_prefix = config.sse_stream_download_path_prefix.rstrip('/')
39
- full_stream_download_path = f"{stream_download_prefix}/{{agent_id_on_server}}/{{stream_id}}"
40
- self._app.router.add_post(rpc_request_path, self.handle_rpc_request)
41
- self._app.router.add_get(full_events_path, self.handle_sse_events_subscription)
42
- self._app.router.add_get(full_stream_download_path, self.handle_http_stream_download)
43
- logger.info(f"SseServerHandler routes: POST {rpc_request_path} (RPC), GET {full_events_path} (SSE per agent), GET {full_stream_download_path} (HTTP Stream Download).")
44
-
45
- async def handle_rpc_request(self, http_request: web.Request) -> web.Response:
46
- # ... (method body remains the same) ...
47
- request_id: Optional[str] = None; raw_body_str: str = ""; target_agent_id: Optional[str] = None
48
- try:
49
- raw_body = await http_request.read(); raw_body_str = raw_body.decode()
50
- try: parsed_json_early = json.loads(raw_body_str); request_id = parsed_json_early.get("id")
51
- except json.JSONDecodeError: pass
52
- request_message = ProtocolMessage.from_json_str(raw_body_str); request_id = request_message.id
53
- if request_message.type != MessageType.REQUEST or not request_message.method:
54
- return self._create_json_error_response(request_id, ErrorCode.INVALID_REQUEST, "Must be REQUEST with method.", 400)
55
- if request_message.params and "target_agent_id" in request_message.params:
56
- target_agent_id = str(request_message.params["target_agent_id"])
57
- if not target_agent_id: return self._create_json_error_response(request_id, ErrorCode.INVALID_PARAMS, "'target_agent_id' missing in request params.", 400)
58
- target_agent = self._agents.get(target_agent_id)
59
- if not target_agent: return self._create_json_error_response(request_id, ErrorCode.METHOD_NOT_FOUND, f"Agent with id '{target_agent_id}' not found.", 404)
60
- actual_handler_params = request_message.params
61
- handler = self._method_handlers.get(request_message.method)
62
- if not handler: return self._create_json_error_response(request_id, ErrorCode.METHOD_NOT_FOUND, f"RPC Method '{request_message.method}' not found.", 404)
63
- logger.debug(f"SseServerHandler dispatching RPC '{request_message.method}' (ReqID: {request_id}) to '{handler.__class__.__name__}' for agent '{target_agent_id}'.")
64
- response_proto = await handler.handle(request_id, actual_handler_params, target_agent)
65
- if response_proto.response_type == ResponseType.STREAM_DOWNLOAD_READY and response_proto.result and "stream_id" in response_proto.result and target_agent_id:
66
- server_config: AgentServerConfig = http_request.app['agent_server_config']
67
- full_url_prefix = server_config.get_sse_full_stream_download_url_prefix_for_agent(target_agent_id)
68
- if full_url_prefix:
69
- stream_id = response_proto.result["stream_id"]; download_url = f"{full_url_prefix.rstrip('/')}/{stream_id}"
70
- response_proto.result["download_url"] = download_url; logger.info(f"Constructed download URL for stream_id '{stream_id}': {download_url}")
71
- else: logger.error(f"Could not construct download_url for stream_id '{response_proto.result['stream_id']}'.")
72
- http_status = 200
73
- if response_proto.type == MessageType.ERROR and response_proto.error:
74
- if response_proto.error.code == ErrorCode.METHOD_NOT_FOUND.value: http_status = 404
75
- elif response_proto.error.code in [ErrorCode.INVALID_REQUEST.value, ErrorCode.INVALID_PARAMS.value, ErrorCode.PARSE_ERROR.value]: http_status = 400
76
- else: http_status = 500
77
- return web.json_response(response_proto.model_dump(exclude_none=True), status=http_status)
78
- except json.JSONDecodeError as e: logger.error(f"Sse JSONDecodeError: {e}. Body: '{raw_body_str[:200]}'"); return self._create_json_error_response(request_id, ErrorCode.PARSE_ERROR, f"JSON parse error: {e}", 400)
79
- except ValueError as e: logger.error(f"Sse Protocol validation error: {e}. Body: '{raw_body_str[:200]}'"); return self._create_json_error_response(request_id, ErrorCode.INVALID_REQUEST, f"Invalid request: {e}", 400)
80
- except Exception as e: logger.error(f"Sse unexpected error: {e}", exc_info=True); return self._create_json_error_response(request_id, ErrorCode.INTERNAL_ERROR, f"Server error: {e}", 500)
81
-
82
- def _create_json_error_response(self, req_id: Optional[str], code: ErrorCode, msg: str, http_status: int) -> web.Response:
83
- # ... (method body remains the same) ...
84
- err_proto = ProtocolMessage.create_error_response(req_id, code, msg)
85
- return web.json_response(err_proto.model_dump(exclude_none=True), status=http_status)
86
-
87
- async def handle_sse_events_subscription(self, http_request: web.Request) -> web.StreamResponse:
88
- # ... (method body remains the same, it instantiates AgentEventStream and calls all_events()) ...
89
- agent_id_on_server = http_request.match_info.get("agent_id_on_server")
90
- if not agent_id_on_server: raise web.HTTPBadRequest(text="'agent_id_on_server' path param required.")
91
- target_agent = self._agents.get(agent_id_on_server)
92
- if not target_agent: raise web.HTTPNotFound(text=f"Agent '{agent_id_on_server}' not found.")
93
- client_addr = http_request.remote
94
- logger.info(f"SSE client {client_addr} subscribing to events for agent '{target_agent.agent_id}' (server key: '{agent_id_on_server}').")
95
- sse_resp = web.StreamResponse(status=200, reason='OK', headers={'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive'})
96
- await sse_resp.prepare(http_request)
97
- forwarding_task = asyncio.create_task(self._stream_agent_events_to_client(sse_resp, target_agent, agent_id_on_server), name=f"sse_fwd_{target_agent.agent_id}_{client_addr}")
98
- self._active_sse_forwarding_tasks[sse_resp] = forwarding_task
99
- try: await forwarding_task
100
- except asyncio.CancelledError: logger.info(f"SSE task for agent '{target_agent.agent_id}' to {client_addr} cancelled.")
101
- except Exception as e: logger.error(f"Error in SSE streaming for agent '{target_agent.agent_id}' to {client_addr}: {e}", exc_info=True)
102
- finally: logger.info(f"SSE client {client_addr} for agent '{target_agent.agent_id}' disconnected."); self._active_sse_forwarding_tasks.pop(sse_resp, None)
103
- return sse_resp
104
-
105
- async def _stream_agent_events_to_client(self, sse_client_resp: web.StreamResponse, agent: Agent, agent_id_on_server: str):
106
- # Instantiates AgentEventStream
107
- event_stream_provider = AgentEventStream(agent)
108
- logger.debug(f"SseServerHandler: Streaming events from agent '{agent.agent_id}' (key: {agent_id_on_server}) via AgentEventStream.all_events().")
109
- try:
110
- # Calls .all_events() method
111
- async for agent_event_obj in event_stream_provider.all_events():
112
- if sse_client_resp.closed: break
113
- rpc_event_type: RPCEventType
114
- if agent_event_obj.event_type == StreamEventType.ASSISTANT_CHUNK: rpc_event_type = RPCEventType.AGENT_OUTPUT_CHUNK
115
- elif agent_event_obj.event_type == StreamEventType.ASSISTANT_FINAL_MESSAGE: rpc_event_type = RPCEventType.AGENT_FINAL_MESSAGE
116
- elif agent_event_obj.event_type == StreamEventType.TOOL_INTERACTION_LOG_ENTRY: rpc_event_type = RPCEventType.TOOL_LOG_ENTRY
117
- elif agent_event_obj.event_type == StreamEventType.AGENT_STATUS_CHANGE: rpc_event_type = RPCEventType.AGENT_STATUS_UPDATE
118
- elif agent_event_obj.event_type == StreamEventType.ERROR_EVENT: rpc_event_type = RPCEventType.AGENT_STATUS_UPDATE; logger.error(f"Unified stream error for agent '{agent.agent_id}': {agent_event_obj.data}")
119
- else: rpc_event_type = RPCEventType.AGENT_STATUS_UPDATE; logger.warning(f"Unhandled StreamEventType '{agent_event_obj.event_type}' from agent '{agent.agent_id}'.")
120
- payload_data = {"agent_id_on_server": agent_id_on_server, **agent_event_obj.data}
121
- protocol_event_msg = ProtocolMessage.create_event(event_type=rpc_event_type, payload=payload_data)
122
- try:
123
- sse_event_str = f"event: {str(protocol_event_msg.event_type.value)}\ndata: {protocol_event_msg.to_json_str()}\n\n"
124
- await sse_client_resp.write(sse_event_str.encode('utf-8'))
125
- except ConnectionResetError: logger.info(f"SSE client reset for agent '{agent.agent_id}'."); break
126
- except Exception as send_e: logger.error(f"Error sending SSE event for agent '{agent.agent_id}': {send_e}"); break
127
- if not sse_client_resp.closed: await sse_client_resp.write_eof()
128
- except asyncio.CancelledError: logger.info(f"Event streaming for agent '{agent.agent_id}' (key: {agent_id_on_server}) cancelled.")
129
- except Exception as e: logger.error(f"Error in event streaming for agent '{agent.agent_id}' (key: {agent_id_on_server}): {e}", exc_info=True)
130
- finally: logger.debug(f"Finished event streaming from agent '{agent.agent_id}' (key: {agent_id_on_server}).")
131
-
132
- async def handle_http_stream_download(self, http_request: web.Request) -> web.StreamResponse:
133
- # ... (method body remains the same) ...
134
- agent_id_on_server = http_request.match_info.get("agent_id_on_server"); stream_id = http_request.match_info.get("stream_id")
135
- if not agent_id_on_server or not stream_id: raise web.HTTPBadRequest(text="'agent_id_on_server' and 'stream_id' path params required.")
136
- target_agent = self._agents.get(agent_id_on_server)
137
- if not target_agent: raise web.HTTPNotFound(text=f"Agent '{agent_id_on_server}' not found.")
138
- logger.info(f"HTTP stream download for agent '{target_agent.agent_id}' (key: '{agent_id_on_server}'), stream_id '{stream_id}'.")
139
- if not hasattr(target_agent, "get_stream_data") or not hasattr(target_agent, "cleanup_stream_resource"):
140
- raise web.HTTPNotImplemented(text=f"Agent '{target_agent.agent_id}' does not support stream retrieval.")
141
- try:
142
- get_stream_data_method = getattr(target_agent, "get_stream_data")
143
- data_iterator: AsyncIterator[bytes] = await get_stream_data_method(stream_id)
144
- response = web.StreamResponse(status=200, reason="OK", headers={"Content-Type": "application/octet-stream"})
145
- await response.prepare(http_request)
146
- async for chunk in data_iterator:
147
- if not isinstance(chunk, bytes): logger.error(f"Agent '{target_agent.agent_id}' stream '{stream_id}' yielded non-bytes: {type(chunk)}."); break
148
- await response.write(chunk); await asyncio.sleep(0)
149
- await response.write_eof(); logger.info(f"Streamed data for agent '{target_agent.agent_id}', stream_id '{stream_id}'."); return response
150
- except FileNotFoundError: logger.warning(f"Stream '{stream_id}' not found for agent '{target_agent.agent_id}'."); raise web.HTTPNotFound(text=f"Stream resource '{stream_id}' not found.")
151
- except asyncio.CancelledError: logger.info(f"HTTP stream download for '{stream_id}' (agent '{target_agent.agent_id}') cancelled."); raise
152
- except Exception as e: logger.error(f"Error during HTTP stream download for '{stream_id}' (agent '{target_agent.agent_id}'): {e}", exc_info=True); raise web.HTTPInternalServerError(text="Error serving stream data.")
153
- finally:
154
- try: cleanup_method = getattr(target_agent, "cleanup_stream_resource"); await cleanup_method(stream_id); logger.debug(f"Agent '{target_agent.agent_id}' cleaned up stream '{stream_id}'.")
155
- except Exception as cleanup_e: logger.error(f"Error cleaning up stream '{stream_id}': {cleanup_e}", exc_info=True)
156
-
157
- async def start_server(self, config: AgentServerConfig):
158
- # ... (method body remains the same) ...
159
- if not config.sse_base_url: raise ValueError("SSE base URL required.")
160
- self._app['agent_server_config'] = config; self._setup_routes(config)
161
- host = config.sse_base_url.host or "0.0.0.0"; port = config.sse_base_url.port or 80
162
- self._runner = web.AppRunner(self._app); await self._runner.setup()
163
- self._site = web.TCPSite(self._runner, host, port)
164
- try: await self._site.start(); logger.info(f"SseServerHandler started for agents {list(self._agents.keys())} on http://{host}:{port}")
165
- except OSError as e: logger.error(f"Failed to start SseServer on http://{host}:{port}: {e}", exc_info=True); await self.stop_server(); raise
166
- except Exception as e: logger.error(f"Unexpected error starting SseServer: {e}", exc_info=True); await self.stop_server(); raise
167
-
168
- async def stop_server(self):
169
- # ... (method body remains the same) ...
170
- logger.info(f"SseServerHandler for agents {list(self._agents.keys())} stopping...")
171
- for task in list(self._active_sse_forwarding_tasks.values()):
172
- if task and not task.done(): task.cancel()
173
- if self._active_sse_forwarding_tasks: await asyncio.gather(*self._active_sse_forwarding_tasks.values(), return_exceptions=True)
174
- self._active_sse_forwarding_tasks.clear()
175
- if self._site: try: await self._site.stop()
176
- except Exception as e: logger.error(f"Error stopping TCPSite: {e}", exc_info=True)
177
- self._site = None
178
- if self._runner: try: await self._runner.cleanup()
179
- except Exception as e: logger.error(f"Error cleaning AppRunner: {e}", exc_info=True)
180
- self._runner = None
181
- logger.info(f"SseServerHandler for agents {list(self._agents.keys())} stopped.")
182
-
@@ -1,151 +0,0 @@
1
- # file: autobyteus/autobyteus/rpc/server/stdio_server_handler.py
2
- import asyncio
3
- import sys
4
- import json
5
- import logging
6
- from typing import Dict, Optional, Union
7
-
8
- from autobyteus.rpc.protocol import ProtocolMessage, MessageType, ErrorCode, RequestType
9
- from autobyteus.rpc.server.base_method_handler import BaseMethodHandler
10
- from autobyteus.agent.agent import Agent # Changed from AgentRuntime
11
-
12
- logger = logging.getLogger(__name__)
13
-
14
- class StdioServerHandler:
15
- """
16
- Handles RPC communication over stdio for an Agent Server.
17
- Reads newline-delimited JSON ProtocolMessages from stdin, dispatches them
18
- to appropriate method handlers (which operate on an Agent instance),
19
- and writes responses to stdout.
20
- """
21
-
22
- def __init__(self, agent: Agent, method_handlers: Dict[Union[RequestType, str], BaseMethodHandler]): # Changed runtime to agent
23
- """
24
- Initializes the StdioServerHandler.
25
-
26
- Args:
27
- agent: The Agent instance this server handler is serving.
28
- method_handlers: A dictionary mapping method names (RequestType or str)
29
- to their handler instances.
30
- """
31
- self._agent = agent # Changed from _runtime to _agent
32
- self._method_handlers = method_handlers
33
- self._running = False
34
- logger.info(f"StdioServerHandler initialized for agent '{self._agent.agent_id}'.") # Use agent.agent_id
35
-
36
- async def listen_and_dispatch(self) -> None:
37
- """
38
- Starts listening on stdin for requests and dispatches them.
39
- This method runs indefinitely until stdin is closed or an error occurs.
40
- """
41
- self._running = True
42
- logger.info(f"StdioServerHandler for agent '{self._agent.agent_id}' now listening on stdin.")
43
-
44
- loop = asyncio.get_event_loop()
45
- reader = asyncio.StreamReader(loop=loop)
46
- protocol = asyncio.StreamReaderProtocol(reader, loop=loop)
47
- await loop.connect_read_pipe(lambda: protocol, sys.stdin)
48
-
49
- try:
50
- while self._running:
51
- line_bytes = await reader.readline()
52
- if not line_bytes:
53
- logger.info(f"StdioServerHandler for agent '{self._agent.agent_id}': stdin EOF reached. Shutting down.")
54
- self._running = False
55
- break
56
-
57
- line_str = line_bytes.decode().strip()
58
- if not line_str:
59
- continue
60
-
61
- request_id: Optional[str] = None
62
- try:
63
- try:
64
- parsed_json = json.loads(line_str)
65
- request_id = parsed_json.get("id")
66
- except json.JSONDecodeError:
67
- pass
68
-
69
- message = ProtocolMessage.from_json_str(line_str)
70
- request_id = message.id
71
-
72
- if message.type == MessageType.REQUEST:
73
- response_message = await self._process_request(message)
74
- else:
75
- logger.warning(f"StdioServerHandler received non-REQUEST message type: {message.type}. Ignoring.")
76
- response_message = ProtocolMessage.create_error_response(
77
- id=request_id,
78
- code=ErrorCode.INVALID_REQUEST,
79
- message="Server only accepts REQUEST messages via stdio."
80
- )
81
-
82
- await self._send_response(response_message)
83
-
84
- except json.JSONDecodeError as e:
85
- logger.error(f"StdioServerHandler: JSONDecodeError: {e}. Raw line: '{line_str[:200]}'")
86
- err_response = ProtocolMessage.create_error_response(
87
- id=request_id,
88
- code=ErrorCode.PARSE_ERROR,
89
- message=f"Failed to parse JSON request: {e}"
90
- )
91
- await self._send_response(err_response)
92
- except ValueError as e:
93
- logger.error(f"StdioServerHandler: ProtocolMessage validation error: {e}. Raw line: '{line_str[:200]}'")
94
- err_response = ProtocolMessage.create_error_response(
95
- id=request_id,
96
- code=ErrorCode.INVALID_REQUEST,
97
- message=f"Invalid request structure: {e}"
98
- )
99
- await self._send_response(err_response)
100
- except Exception as e:
101
- logger.error(f"StdioServerHandler: Unexpected error processing line: {e}. Raw line: '{line_str[:200]}'", exc_info=True)
102
- err_response = ProtocolMessage.create_error_response(
103
- id=request_id,
104
- code=ErrorCode.INTERNAL_ERROR,
105
- message=f"Internal server error: {e}"
106
- )
107
- await self._send_response(err_response)
108
-
109
- except asyncio.CancelledError:
110
- logger.info(f"StdioServerHandler for agent '{self._agent.agent_id}' listen_and_dispatch task cancelled.")
111
- except Exception as e:
112
- logger.error(f"StdioServerHandler for agent '{self._agent.agent_id}' fatal error in listen_and_dispatch: {e}", exc_info=True)
113
- finally:
114
- self._running = False
115
- logger.info(f"StdioServerHandler for agent '{self._agent.agent_id}' stopped listening.")
116
-
117
- async def _process_request(self, request_message: ProtocolMessage) -> ProtocolMessage:
118
- if not request_message.method:
119
- logger.warning(f"StdioServerHandler: Request message missing 'method'. ID: {request_message.id}")
120
- return ProtocolMessage.create_error_response(
121
- id=request_message.id,
122
- code=ErrorCode.INVALID_REQUEST,
123
- message="Request message must include a 'method'."
124
- )
125
-
126
- handler = self._method_handlers.get(request_message.method)
127
- if not handler:
128
- logger.warning(f"StdioServerHandler: No handler found for method '{request_message.method}'. ID: {request_message.id}")
129
- return ProtocolMessage.create_error_response(
130
- id=request_message.id,
131
- code=ErrorCode.METHOD_NOT_FOUND,
132
- message=f"Method '{request_message.method}' not found."
133
- )
134
-
135
- logger.debug(f"StdioServerHandler dispatching method '{request_message.method}' (ID: {request_message.id}) to {handler.__class__.__name__}.")
136
- return await handler.handle(request_message.id, request_message.params, self._agent) # Pass self._agent
137
-
138
- async def _send_response(self, response_message: ProtocolMessage) -> None:
139
- try:
140
- json_response = response_message.to_json_str()
141
- loop = asyncio.get_event_loop()
142
- await loop.run_in_executor(None, lambda: sys.stdout.write(json_response + '\n'))
143
- await loop.run_in_executor(None, sys.stdout.flush)
144
- logger.debug(f"StdioServerHandler sent response (ID: {response_message.id}, Type: {response_message.type}).")
145
- except Exception as e:
146
- logger.error(f"StdioServerHandler failed to send response: {e}", exc_info=True)
147
-
148
- def stop(self):
149
- logger.info(f"StdioServerHandler for agent '{self._agent.agent_id}' stop requested.")
150
- self._running = False
151
-