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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (512) hide show
  1. autobyteus/agent/agent.py +15 -5
  2. autobyteus/agent/bootstrap_steps/__init__.py +1 -3
  3. autobyteus/agent/bootstrap_steps/agent_bootstrapper.py +3 -59
  4. autobyteus/agent/bootstrap_steps/base_bootstrap_step.py +1 -4
  5. autobyteus/agent/bootstrap_steps/mcp_server_prewarming_step.py +1 -3
  6. autobyteus/agent/bootstrap_steps/system_prompt_processing_step.py +16 -13
  7. autobyteus/agent/bootstrap_steps/workspace_context_initialization_step.py +2 -4
  8. autobyteus/agent/context/agent_config.py +43 -20
  9. autobyteus/agent/context/agent_context.py +23 -18
  10. autobyteus/agent/context/agent_runtime_state.py +23 -19
  11. autobyteus/agent/events/__init__.py +16 -1
  12. autobyteus/agent/events/agent_events.py +43 -3
  13. autobyteus/agent/events/agent_input_event_queue_manager.py +79 -26
  14. autobyteus/agent/events/event_store.py +57 -0
  15. autobyteus/agent/events/notifiers.py +74 -60
  16. autobyteus/agent/events/worker_event_dispatcher.py +21 -64
  17. autobyteus/agent/factory/agent_factory.py +52 -0
  18. autobyteus/agent/handlers/__init__.py +2 -0
  19. autobyteus/agent/handlers/approved_tool_invocation_event_handler.py +51 -34
  20. autobyteus/agent/handlers/bootstrap_event_handler.py +155 -0
  21. autobyteus/agent/handlers/inter_agent_message_event_handler.py +10 -0
  22. autobyteus/agent/handlers/lifecycle_event_logger.py +19 -11
  23. autobyteus/agent/handlers/llm_complete_response_received_event_handler.py +10 -15
  24. autobyteus/agent/handlers/llm_user_message_ready_event_handler.py +188 -48
  25. autobyteus/agent/handlers/tool_execution_approval_event_handler.py +0 -10
  26. autobyteus/agent/handlers/tool_invocation_request_event_handler.py +53 -48
  27. autobyteus/agent/handlers/tool_result_event_handler.py +7 -8
  28. autobyteus/agent/handlers/user_input_message_event_handler.py +10 -3
  29. autobyteus/agent/input_processor/memory_ingest_input_processor.py +40 -0
  30. autobyteus/agent/lifecycle/__init__.py +12 -0
  31. autobyteus/agent/lifecycle/base_processor.py +109 -0
  32. autobyteus/agent/lifecycle/events.py +35 -0
  33. autobyteus/agent/lifecycle/processor_definition.py +36 -0
  34. autobyteus/agent/lifecycle/processor_registry.py +106 -0
  35. autobyteus/agent/llm_request_assembler.py +98 -0
  36. autobyteus/agent/llm_response_processor/__init__.py +1 -8
  37. autobyteus/agent/message/context_file_type.py +1 -1
  38. autobyteus/agent/message/send_message_to.py +5 -4
  39. autobyteus/agent/runtime/agent_runtime.py +29 -21
  40. autobyteus/agent/runtime/agent_worker.py +98 -19
  41. autobyteus/agent/shutdown_steps/__init__.py +2 -0
  42. autobyteus/agent/shutdown_steps/agent_shutdown_orchestrator.py +2 -0
  43. autobyteus/agent/shutdown_steps/tool_cleanup_step.py +58 -0
  44. autobyteus/agent/status/__init__.py +14 -0
  45. autobyteus/agent/status/manager.py +93 -0
  46. autobyteus/agent/status/status_deriver.py +96 -0
  47. autobyteus/agent/{phases/phase_enum.py → status/status_enum.py} +16 -16
  48. autobyteus/agent/status/status_update_utils.py +73 -0
  49. autobyteus/agent/streaming/__init__.py +52 -5
  50. autobyteus/agent/streaming/adapters/__init__.py +18 -0
  51. autobyteus/agent/streaming/adapters/invocation_adapter.py +184 -0
  52. autobyteus/agent/streaming/adapters/tool_call_parsing.py +163 -0
  53. autobyteus/agent/streaming/adapters/tool_syntax_registry.py +67 -0
  54. autobyteus/agent/streaming/agent_event_stream.py +3 -178
  55. autobyteus/agent/streaming/api_tool_call/__init__.py +16 -0
  56. autobyteus/agent/streaming/api_tool_call/file_content_streamer.py +56 -0
  57. autobyteus/agent/streaming/api_tool_call/json_string_field_extractor.py +175 -0
  58. autobyteus/agent/streaming/api_tool_call_streaming_response_handler.py +4 -0
  59. autobyteus/agent/streaming/events/__init__.py +6 -0
  60. autobyteus/agent/streaming/events/stream_event_payloads.py +284 -0
  61. autobyteus/agent/streaming/events/stream_events.py +141 -0
  62. autobyteus/agent/streaming/handlers/__init__.py +15 -0
  63. autobyteus/agent/streaming/handlers/api_tool_call_streaming_response_handler.py +303 -0
  64. autobyteus/agent/streaming/handlers/parsing_streaming_response_handler.py +107 -0
  65. autobyteus/agent/streaming/handlers/pass_through_streaming_response_handler.py +107 -0
  66. autobyteus/agent/streaming/handlers/streaming_handler_factory.py +177 -0
  67. autobyteus/agent/streaming/handlers/streaming_response_handler.py +58 -0
  68. autobyteus/agent/streaming/parser/__init__.py +61 -0
  69. autobyteus/agent/streaming/parser/event_emitter.py +181 -0
  70. autobyteus/agent/streaming/parser/events.py +4 -0
  71. autobyteus/agent/streaming/parser/invocation_adapter.py +4 -0
  72. autobyteus/agent/streaming/parser/json_parsing_strategies/__init__.py +19 -0
  73. autobyteus/agent/streaming/parser/json_parsing_strategies/base.py +32 -0
  74. autobyteus/agent/streaming/parser/json_parsing_strategies/default.py +34 -0
  75. autobyteus/agent/streaming/parser/json_parsing_strategies/gemini.py +31 -0
  76. autobyteus/agent/streaming/parser/json_parsing_strategies/openai.py +64 -0
  77. autobyteus/agent/streaming/parser/json_parsing_strategies/registry.py +75 -0
  78. autobyteus/agent/streaming/parser/parser_context.py +227 -0
  79. autobyteus/agent/streaming/parser/parser_factory.py +132 -0
  80. autobyteus/agent/streaming/parser/sentinel_format.py +7 -0
  81. autobyteus/agent/streaming/parser/state_factory.py +62 -0
  82. autobyteus/agent/streaming/parser/states/__init__.py +1 -0
  83. autobyteus/agent/streaming/parser/states/base_state.py +60 -0
  84. autobyteus/agent/streaming/parser/states/custom_xml_tag_run_bash_parsing_state.py +38 -0
  85. autobyteus/agent/streaming/parser/states/custom_xml_tag_write_file_parsing_state.py +55 -0
  86. autobyteus/agent/streaming/parser/states/delimited_content_state.py +146 -0
  87. autobyteus/agent/streaming/parser/states/json_initialization_state.py +144 -0
  88. autobyteus/agent/streaming/parser/states/json_tool_parsing_state.py +137 -0
  89. autobyteus/agent/streaming/parser/states/sentinel_content_state.py +30 -0
  90. autobyteus/agent/streaming/parser/states/sentinel_initialization_state.py +117 -0
  91. autobyteus/agent/streaming/parser/states/text_state.py +78 -0
  92. autobyteus/agent/streaming/parser/states/xml_patch_file_tool_parsing_state.py +328 -0
  93. autobyteus/agent/streaming/parser/states/xml_run_bash_tool_parsing_state.py +129 -0
  94. autobyteus/agent/streaming/parser/states/xml_tag_initialization_state.py +151 -0
  95. autobyteus/agent/streaming/parser/states/xml_tool_parsing_state.py +63 -0
  96. autobyteus/agent/streaming/parser/states/xml_write_file_tool_parsing_state.py +343 -0
  97. autobyteus/agent/streaming/parser/strategies/__init__.py +17 -0
  98. autobyteus/agent/streaming/parser/strategies/base.py +24 -0
  99. autobyteus/agent/streaming/parser/strategies/json_tool_strategy.py +26 -0
  100. autobyteus/agent/streaming/parser/strategies/registry.py +28 -0
  101. autobyteus/agent/streaming/parser/strategies/sentinel_strategy.py +23 -0
  102. autobyteus/agent/streaming/parser/strategies/xml_tag_strategy.py +21 -0
  103. autobyteus/agent/streaming/parser/stream_scanner.py +167 -0
  104. autobyteus/agent/streaming/parser/streaming_parser.py +212 -0
  105. autobyteus/agent/streaming/parser/tool_call_parsing.py +4 -0
  106. autobyteus/agent/streaming/parser/tool_constants.py +7 -0
  107. autobyteus/agent/streaming/parser/tool_syntax_registry.py +4 -0
  108. autobyteus/agent/streaming/parser/xml_tool_parsing_state_registry.py +55 -0
  109. autobyteus/agent/streaming/parsing_streaming_response_handler.py +4 -0
  110. autobyteus/agent/streaming/pass_through_streaming_response_handler.py +4 -0
  111. autobyteus/agent/streaming/queue_streamer.py +3 -57
  112. autobyteus/agent/streaming/segments/__init__.py +5 -0
  113. autobyteus/agent/streaming/segments/segment_events.py +81 -0
  114. autobyteus/agent/streaming/stream_event_payloads.py +2 -198
  115. autobyteus/agent/streaming/stream_events.py +3 -128
  116. autobyteus/agent/streaming/streaming_handler_factory.py +4 -0
  117. autobyteus/agent/streaming/streaming_response_handler.py +4 -0
  118. autobyteus/agent/streaming/streams/__init__.py +5 -0
  119. autobyteus/agent/streaming/streams/agent_event_stream.py +197 -0
  120. autobyteus/agent/streaming/utils/__init__.py +5 -0
  121. autobyteus/agent/streaming/utils/queue_streamer.py +59 -0
  122. autobyteus/agent/system_prompt_processor/__init__.py +2 -0
  123. autobyteus/agent/system_prompt_processor/available_skills_processor.py +96 -0
  124. autobyteus/agent/system_prompt_processor/base_processor.py +1 -1
  125. autobyteus/agent/system_prompt_processor/processor_meta.py +15 -2
  126. autobyteus/agent/system_prompt_processor/tool_manifest_injector_processor.py +39 -58
  127. autobyteus/agent/token_budget.py +56 -0
  128. autobyteus/agent/tool_execution_result_processor/memory_ingest_tool_result_processor.py +29 -0
  129. autobyteus/agent/tool_invocation.py +16 -40
  130. autobyteus/agent/tool_invocation_preprocessor/__init__.py +9 -0
  131. autobyteus/agent/tool_invocation_preprocessor/base_preprocessor.py +45 -0
  132. autobyteus/agent/tool_invocation_preprocessor/processor_definition.py +15 -0
  133. autobyteus/agent/tool_invocation_preprocessor/processor_meta.py +33 -0
  134. autobyteus/agent/tool_invocation_preprocessor/processor_registry.py +60 -0
  135. autobyteus/agent/utils/wait_for_idle.py +12 -14
  136. autobyteus/agent/workspace/base_workspace.py +6 -27
  137. autobyteus/agent_team/agent_team.py +3 -3
  138. autobyteus/agent_team/agent_team_builder.py +1 -41
  139. autobyteus/agent_team/bootstrap_steps/__init__.py +0 -4
  140. autobyteus/agent_team/bootstrap_steps/agent_configuration_preparation_step.py +8 -18
  141. autobyteus/agent_team/bootstrap_steps/agent_team_bootstrapper.py +4 -16
  142. autobyteus/agent_team/bootstrap_steps/base_agent_team_bootstrap_step.py +1 -2
  143. autobyteus/agent_team/bootstrap_steps/coordinator_initialization_step.py +1 -2
  144. autobyteus/agent_team/bootstrap_steps/task_notifier_initialization_step.py +5 -6
  145. autobyteus/agent_team/bootstrap_steps/team_context_initialization_step.py +15 -15
  146. autobyteus/agent_team/context/agent_team_config.py +6 -3
  147. autobyteus/agent_team/context/agent_team_context.py +25 -3
  148. autobyteus/agent_team/context/agent_team_runtime_state.py +11 -8
  149. autobyteus/agent_team/events/__init__.py +11 -0
  150. autobyteus/agent_team/events/agent_team_event_dispatcher.py +22 -9
  151. autobyteus/agent_team/events/agent_team_events.py +16 -0
  152. autobyteus/agent_team/events/event_store.py +57 -0
  153. autobyteus/agent_team/factory/agent_team_factory.py +8 -0
  154. autobyteus/agent_team/handlers/inter_agent_message_request_event_handler.py +18 -2
  155. autobyteus/agent_team/handlers/lifecycle_agent_team_event_handler.py +21 -5
  156. autobyteus/agent_team/handlers/process_user_message_event_handler.py +17 -8
  157. autobyteus/agent_team/handlers/tool_approval_team_event_handler.py +19 -4
  158. autobyteus/agent_team/runtime/agent_team_runtime.py +41 -10
  159. autobyteus/agent_team/runtime/agent_team_worker.py +69 -5
  160. autobyteus/agent_team/status/__init__.py +14 -0
  161. autobyteus/agent_team/status/agent_team_status.py +18 -0
  162. autobyteus/agent_team/status/agent_team_status_manager.py +33 -0
  163. autobyteus/agent_team/status/status_deriver.py +62 -0
  164. autobyteus/agent_team/status/status_update_utils.py +42 -0
  165. autobyteus/agent_team/streaming/__init__.py +2 -2
  166. autobyteus/agent_team/streaming/agent_team_event_notifier.py +10 -10
  167. autobyteus/agent_team/streaming/agent_team_stream_event_payloads.py +7 -7
  168. autobyteus/agent_team/streaming/agent_team_stream_events.py +11 -11
  169. autobyteus/agent_team/system_prompt_processor/__init__.py +6 -0
  170. autobyteus/agent_team/system_prompt_processor/team_manifest_injector_processor.py +76 -0
  171. autobyteus/agent_team/task_notification/activation_policy.py +1 -1
  172. autobyteus/agent_team/task_notification/system_event_driven_agent_task_notifier.py +22 -22
  173. autobyteus/agent_team/task_notification/task_notification_mode.py +20 -1
  174. autobyteus/agent_team/utils/wait_for_idle.py +4 -4
  175. autobyteus/cli/agent_cli.py +18 -10
  176. autobyteus/cli/agent_team_tui/app.py +18 -15
  177. autobyteus/cli/agent_team_tui/state.py +21 -23
  178. autobyteus/cli/agent_team_tui/widgets/agent_list_sidebar.py +15 -15
  179. autobyteus/cli/agent_team_tui/widgets/focus_pane.py +146 -39
  180. autobyteus/cli/agent_team_tui/widgets/renderables.py +1 -1
  181. autobyteus/cli/agent_team_tui/widgets/shared.py +26 -26
  182. autobyteus/cli/agent_team_tui/widgets/{task_board_panel.py → task_plan_panel.py} +5 -5
  183. autobyteus/cli/cli_display.py +193 -44
  184. autobyteus/cli/workflow_tui/app.py +9 -10
  185. autobyteus/cli/workflow_tui/state.py +14 -16
  186. autobyteus/cli/workflow_tui/widgets/agent_list_sidebar.py +15 -15
  187. autobyteus/cli/workflow_tui/widgets/focus_pane.py +137 -35
  188. autobyteus/cli/workflow_tui/widgets/renderables.py +1 -1
  189. autobyteus/cli/workflow_tui/widgets/shared.py +25 -25
  190. autobyteus/clients/autobyteus_client.py +94 -1
  191. autobyteus/events/event_types.py +15 -21
  192. autobyteus/llm/api/autobyteus_llm.py +33 -29
  193. autobyteus/llm/api/claude_llm.py +142 -36
  194. autobyteus/llm/api/gemini_llm.py +163 -59
  195. autobyteus/llm/api/grok_llm.py +1 -1
  196. autobyteus/llm/api/minimax_llm.py +26 -0
  197. autobyteus/llm/api/mistral_llm.py +113 -87
  198. autobyteus/llm/api/ollama_llm.py +9 -42
  199. autobyteus/llm/api/openai_compatible_llm.py +127 -91
  200. autobyteus/llm/api/openai_llm.py +3 -3
  201. autobyteus/llm/api/openai_responses_llm.py +324 -0
  202. autobyteus/llm/api/zhipu_llm.py +21 -2
  203. autobyteus/llm/autobyteus_provider.py +70 -60
  204. autobyteus/llm/base_llm.py +85 -81
  205. autobyteus/llm/converters/__init__.py +14 -0
  206. autobyteus/llm/converters/anthropic_tool_call_converter.py +37 -0
  207. autobyteus/llm/converters/gemini_tool_call_converter.py +57 -0
  208. autobyteus/llm/converters/mistral_tool_call_converter.py +37 -0
  209. autobyteus/llm/converters/openai_tool_call_converter.py +38 -0
  210. autobyteus/llm/extensions/base_extension.py +6 -12
  211. autobyteus/llm/extensions/token_usage_tracking_extension.py +45 -18
  212. autobyteus/llm/llm_factory.py +282 -204
  213. autobyteus/llm/lmstudio_provider.py +60 -49
  214. autobyteus/llm/models.py +35 -2
  215. autobyteus/llm/ollama_provider.py +60 -49
  216. autobyteus/llm/ollama_provider_resolver.py +0 -1
  217. autobyteus/llm/prompt_renderers/__init__.py +19 -0
  218. autobyteus/llm/prompt_renderers/anthropic_prompt_renderer.py +104 -0
  219. autobyteus/llm/prompt_renderers/autobyteus_prompt_renderer.py +19 -0
  220. autobyteus/llm/prompt_renderers/base_prompt_renderer.py +10 -0
  221. autobyteus/llm/prompt_renderers/gemini_prompt_renderer.py +63 -0
  222. autobyteus/llm/prompt_renderers/mistral_prompt_renderer.py +87 -0
  223. autobyteus/llm/prompt_renderers/ollama_prompt_renderer.py +51 -0
  224. autobyteus/llm/prompt_renderers/openai_chat_renderer.py +97 -0
  225. autobyteus/llm/prompt_renderers/openai_responses_renderer.py +101 -0
  226. autobyteus/llm/providers.py +1 -3
  227. autobyteus/llm/token_counter/claude_token_counter.py +56 -25
  228. autobyteus/llm/token_counter/mistral_token_counter.py +12 -8
  229. autobyteus/llm/token_counter/openai_token_counter.py +24 -5
  230. autobyteus/llm/token_counter/token_counter_factory.py +12 -5
  231. autobyteus/llm/utils/llm_config.py +6 -12
  232. autobyteus/llm/utils/media_payload_formatter.py +27 -20
  233. autobyteus/llm/utils/messages.py +55 -3
  234. autobyteus/llm/utils/response_types.py +3 -0
  235. autobyteus/llm/utils/tool_call_delta.py +31 -0
  236. autobyteus/memory/__init__.py +32 -0
  237. autobyteus/memory/active_transcript.py +69 -0
  238. autobyteus/memory/compaction/__init__.py +9 -0
  239. autobyteus/memory/compaction/compaction_result.py +8 -0
  240. autobyteus/memory/compaction/compactor.py +89 -0
  241. autobyteus/memory/compaction/summarizer.py +11 -0
  242. autobyteus/memory/compaction_snapshot_builder.py +84 -0
  243. autobyteus/memory/memory_manager.py +183 -0
  244. autobyteus/memory/models/__init__.py +14 -0
  245. autobyteus/memory/models/episodic_item.py +41 -0
  246. autobyteus/memory/models/memory_types.py +7 -0
  247. autobyteus/memory/models/raw_trace_item.py +79 -0
  248. autobyteus/memory/models/semantic_item.py +41 -0
  249. autobyteus/memory/models/tool_interaction.py +20 -0
  250. autobyteus/memory/policies/__init__.py +5 -0
  251. autobyteus/memory/policies/compaction_policy.py +16 -0
  252. autobyteus/memory/retrieval/__init__.py +7 -0
  253. autobyteus/memory/retrieval/memory_bundle.py +11 -0
  254. autobyteus/memory/retrieval/retriever.py +13 -0
  255. autobyteus/memory/store/__init__.py +7 -0
  256. autobyteus/memory/store/base_store.py +14 -0
  257. autobyteus/memory/store/file_store.py +98 -0
  258. autobyteus/memory/tool_interaction_builder.py +46 -0
  259. autobyteus/memory/turn_tracker.py +9 -0
  260. autobyteus/multimedia/audio/api/__init__.py +3 -2
  261. autobyteus/multimedia/audio/api/autobyteus_audio_client.py +19 -5
  262. autobyteus/multimedia/audio/api/gemini_audio_client.py +108 -16
  263. autobyteus/multimedia/audio/api/openai_audio_client.py +112 -0
  264. autobyteus/multimedia/audio/audio_client_factory.py +84 -9
  265. autobyteus/multimedia/audio/audio_model.py +2 -1
  266. autobyteus/multimedia/image/api/autobyteus_image_client.py +19 -5
  267. autobyteus/multimedia/image/api/gemini_image_client.py +38 -17
  268. autobyteus/multimedia/image/api/openai_image_client.py +125 -43
  269. autobyteus/multimedia/image/autobyteus_image_provider.py +2 -1
  270. autobyteus/multimedia/image/image_client_factory.py +47 -15
  271. autobyteus/multimedia/image/image_model.py +5 -2
  272. autobyteus/multimedia/providers.py +3 -2
  273. autobyteus/skills/loader.py +71 -0
  274. autobyteus/skills/model.py +11 -0
  275. autobyteus/skills/registry.py +70 -0
  276. autobyteus/task_management/__init__.py +43 -20
  277. autobyteus/task_management/{base_task_board.py → base_task_plan.py} +16 -13
  278. autobyteus/task_management/converters/__init__.py +2 -2
  279. autobyteus/task_management/converters/{task_board_converter.py → task_plan_converter.py} +13 -13
  280. autobyteus/task_management/events.py +7 -7
  281. autobyteus/task_management/{in_memory_task_board.py → in_memory_task_plan.py} +34 -22
  282. autobyteus/task_management/schemas/__init__.py +3 -0
  283. autobyteus/task_management/schemas/task_status_report.py +2 -2
  284. autobyteus/task_management/schemas/todo_definition.py +15 -0
  285. autobyteus/task_management/todo.py +29 -0
  286. autobyteus/task_management/todo_list.py +75 -0
  287. autobyteus/task_management/tools/__init__.py +24 -8
  288. autobyteus/task_management/tools/task_tools/__init__.py +19 -0
  289. autobyteus/task_management/tools/{assign_task_to.py → task_tools/assign_task_to.py} +18 -18
  290. autobyteus/task_management/tools/{publish_task.py → task_tools/create_task.py} +16 -18
  291. autobyteus/task_management/tools/{publish_tasks.py → task_tools/create_tasks.py} +19 -19
  292. autobyteus/task_management/tools/{get_my_tasks.py → task_tools/get_my_tasks.py} +15 -15
  293. autobyteus/task_management/tools/{get_task_board_status.py → task_tools/get_task_plan_status.py} +16 -16
  294. autobyteus/task_management/tools/{update_task_status.py → task_tools/update_task_status.py} +16 -16
  295. autobyteus/task_management/tools/todo_tools/__init__.py +18 -0
  296. autobyteus/task_management/tools/todo_tools/add_todo.py +78 -0
  297. autobyteus/task_management/tools/todo_tools/create_todo_list.py +79 -0
  298. autobyteus/task_management/tools/todo_tools/get_todo_list.py +55 -0
  299. autobyteus/task_management/tools/todo_tools/update_todo_status.py +85 -0
  300. autobyteus/tools/__init__.py +43 -52
  301. autobyteus/tools/base_tool.py +7 -0
  302. autobyteus/tools/file/__init__.py +9 -0
  303. autobyteus/tools/file/patch_file.py +149 -0
  304. autobyteus/tools/file/{file_reader.py → read_file.py} +38 -7
  305. autobyteus/tools/file/{file_writer.py → write_file.py} +7 -4
  306. autobyteus/tools/functional_tool.py +53 -14
  307. autobyteus/tools/mcp/__init__.py +2 -0
  308. autobyteus/tools/mcp/config_service.py +5 -1
  309. autobyteus/tools/mcp/server/__init__.py +2 -0
  310. autobyteus/tools/mcp/server/http_managed_mcp_server.py +1 -1
  311. autobyteus/tools/mcp/server/websocket_managed_mcp_server.py +141 -0
  312. autobyteus/tools/mcp/server_instance_manager.py +8 -1
  313. autobyteus/tools/mcp/tool.py +3 -3
  314. autobyteus/tools/mcp/tool_registrar.py +5 -2
  315. autobyteus/tools/mcp/types.py +61 -0
  316. autobyteus/tools/multimedia/__init__.py +2 -1
  317. autobyteus/tools/multimedia/audio_tools.py +72 -19
  318. autobyteus/tools/{download_media_tool.py → multimedia/download_media_tool.py} +21 -7
  319. autobyteus/tools/multimedia/image_tools.py +248 -64
  320. autobyteus/tools/multimedia/media_reader_tool.py +1 -1
  321. autobyteus/tools/operation_executor/journal_manager.py +107 -0
  322. autobyteus/tools/operation_executor/operation_event_buffer.py +57 -0
  323. autobyteus/tools/operation_executor/operation_event_producer.py +29 -0
  324. autobyteus/tools/operation_executor/operation_executor.py +58 -0
  325. autobyteus/tools/registry/tool_definition.py +108 -14
  326. autobyteus/tools/registry/tool_registry.py +29 -0
  327. autobyteus/tools/search/__init__.py +17 -0
  328. autobyteus/tools/search/base_strategy.py +35 -0
  329. autobyteus/tools/search/client.py +24 -0
  330. autobyteus/tools/search/factory.py +81 -0
  331. autobyteus/tools/search/google_cse_strategy.py +68 -0
  332. autobyteus/tools/search/providers.py +10 -0
  333. autobyteus/tools/search/serpapi_strategy.py +65 -0
  334. autobyteus/tools/search/serper_strategy.py +87 -0
  335. autobyteus/tools/search_tool.py +83 -0
  336. autobyteus/tools/skill/load_skill.py +50 -0
  337. autobyteus/tools/terminal/__init__.py +45 -0
  338. autobyteus/tools/terminal/ansi_utils.py +32 -0
  339. autobyteus/tools/terminal/background_process_manager.py +233 -0
  340. autobyteus/tools/terminal/output_buffer.py +105 -0
  341. autobyteus/tools/terminal/prompt_detector.py +63 -0
  342. autobyteus/tools/terminal/pty_session.py +241 -0
  343. autobyteus/tools/terminal/session_factory.py +20 -0
  344. autobyteus/tools/terminal/terminal_session_manager.py +226 -0
  345. autobyteus/tools/terminal/tools/__init__.py +13 -0
  346. autobyteus/tools/terminal/tools/get_process_output.py +81 -0
  347. autobyteus/tools/terminal/tools/run_bash.py +109 -0
  348. autobyteus/tools/terminal/tools/start_background_process.py +104 -0
  349. autobyteus/tools/terminal/tools/stop_background_process.py +67 -0
  350. autobyteus/tools/terminal/types.py +54 -0
  351. autobyteus/tools/terminal/wsl_tmux_session.py +221 -0
  352. autobyteus/tools/terminal/wsl_utils.py +156 -0
  353. autobyteus/tools/tool_meta.py +4 -24
  354. autobyteus/tools/transaction_management/backup_handler.py +48 -0
  355. autobyteus/tools/transaction_management/operation_lifecycle_manager.py +62 -0
  356. autobyteus/tools/usage/__init__.py +1 -2
  357. autobyteus/tools/usage/formatters/__init__.py +17 -1
  358. autobyteus/tools/usage/formatters/base_formatter.py +8 -0
  359. autobyteus/tools/usage/formatters/default_xml_schema_formatter.py +2 -2
  360. autobyteus/tools/usage/formatters/mistral_json_schema_formatter.py +18 -0
  361. autobyteus/tools/usage/formatters/patch_file_xml_example_formatter.py +64 -0
  362. autobyteus/tools/usage/formatters/patch_file_xml_schema_formatter.py +31 -0
  363. autobyteus/tools/usage/formatters/run_bash_xml_example_formatter.py +32 -0
  364. autobyteus/tools/usage/formatters/run_bash_xml_schema_formatter.py +36 -0
  365. autobyteus/tools/usage/formatters/write_file_xml_example_formatter.py +53 -0
  366. autobyteus/tools/usage/formatters/write_file_xml_schema_formatter.py +31 -0
  367. autobyteus/tools/usage/providers/tool_manifest_provider.py +10 -10
  368. autobyteus/tools/usage/registries/__init__.py +1 -3
  369. autobyteus/tools/usage/registries/tool_formatting_registry.py +115 -8
  370. autobyteus/tools/usage/tool_schema_provider.py +51 -0
  371. autobyteus/tools/web/__init__.py +4 -0
  372. autobyteus/tools/web/read_url_tool.py +80 -0
  373. autobyteus/utils/diff_utils.py +271 -0
  374. autobyteus/utils/download_utils.py +109 -0
  375. autobyteus/utils/file_utils.py +57 -2
  376. autobyteus/utils/gemini_helper.py +56 -0
  377. autobyteus/utils/gemini_model_mapping.py +71 -0
  378. autobyteus/utils/llm_output_formatter.py +75 -0
  379. autobyteus/utils/tool_call_format.py +36 -0
  380. autobyteus/workflow/agentic_workflow.py +3 -3
  381. autobyteus/workflow/bootstrap_steps/agent_tool_injection_step.py +2 -2
  382. autobyteus/workflow/bootstrap_steps/base_workflow_bootstrap_step.py +2 -2
  383. autobyteus/workflow/bootstrap_steps/coordinator_initialization_step.py +2 -2
  384. autobyteus/workflow/bootstrap_steps/coordinator_prompt_preparation_step.py +4 -11
  385. autobyteus/workflow/bootstrap_steps/workflow_bootstrapper.py +6 -6
  386. autobyteus/workflow/bootstrap_steps/workflow_runtime_queue_initialization_step.py +2 -2
  387. autobyteus/workflow/context/workflow_context.py +3 -3
  388. autobyteus/workflow/context/workflow_runtime_state.py +5 -5
  389. autobyteus/workflow/events/workflow_event_dispatcher.py +5 -5
  390. autobyteus/workflow/handlers/lifecycle_workflow_event_handler.py +3 -3
  391. autobyteus/workflow/handlers/process_user_message_event_handler.py +5 -5
  392. autobyteus/workflow/handlers/tool_approval_workflow_event_handler.py +2 -2
  393. autobyteus/workflow/runtime/workflow_runtime.py +8 -8
  394. autobyteus/workflow/runtime/workflow_worker.py +3 -3
  395. autobyteus/workflow/status/__init__.py +11 -0
  396. autobyteus/workflow/status/workflow_status.py +19 -0
  397. autobyteus/workflow/status/workflow_status_manager.py +48 -0
  398. autobyteus/workflow/streaming/__init__.py +2 -2
  399. autobyteus/workflow/streaming/workflow_event_notifier.py +7 -7
  400. autobyteus/workflow/streaming/workflow_stream_event_payloads.py +4 -4
  401. autobyteus/workflow/streaming/workflow_stream_events.py +3 -3
  402. autobyteus/workflow/utils/wait_for_idle.py +4 -4
  403. autobyteus-1.2.3.dist-info/METADATA +293 -0
  404. autobyteus-1.2.3.dist-info/RECORD +600 -0
  405. {autobyteus-1.2.0.dist-info → autobyteus-1.2.3.dist-info}/WHEEL +1 -1
  406. {autobyteus-1.2.0.dist-info → autobyteus-1.2.3.dist-info}/top_level.txt +0 -1
  407. autobyteus/agent/bootstrap_steps/agent_runtime_queue_initialization_step.py +0 -57
  408. autobyteus/agent/hooks/__init__.py +0 -16
  409. autobyteus/agent/hooks/base_phase_hook.py +0 -78
  410. autobyteus/agent/hooks/hook_definition.py +0 -36
  411. autobyteus/agent/hooks/hook_meta.py +0 -37
  412. autobyteus/agent/hooks/hook_registry.py +0 -106
  413. autobyteus/agent/llm_response_processor/provider_aware_tool_usage_processor.py +0 -103
  414. autobyteus/agent/phases/__init__.py +0 -18
  415. autobyteus/agent/phases/discover.py +0 -53
  416. autobyteus/agent/phases/manager.py +0 -265
  417. autobyteus/agent/phases/transition_decorator.py +0 -40
  418. autobyteus/agent/phases/transition_info.py +0 -33
  419. autobyteus/agent/remote_agent.py +0 -244
  420. autobyteus/agent/workspace/workspace_definition.py +0 -36
  421. autobyteus/agent/workspace/workspace_meta.py +0 -37
  422. autobyteus/agent/workspace/workspace_registry.py +0 -72
  423. autobyteus/agent_team/bootstrap_steps/agent_team_runtime_queue_initialization_step.py +0 -25
  424. autobyteus/agent_team/bootstrap_steps/coordinator_prompt_preparation_step.py +0 -85
  425. autobyteus/agent_team/phases/__init__.py +0 -11
  426. autobyteus/agent_team/phases/agent_team_operational_phase.py +0 -19
  427. autobyteus/agent_team/phases/agent_team_phase_manager.py +0 -48
  428. autobyteus/llm/api/bedrock_llm.py +0 -92
  429. autobyteus/llm/api/groq_llm.py +0 -94
  430. autobyteus/llm/api/nvidia_llm.py +0 -108
  431. autobyteus/llm/utils/token_pricing_config.py +0 -87
  432. autobyteus/person/examples/sample_persons.py +0 -14
  433. autobyteus/person/examples/sample_roles.py +0 -14
  434. autobyteus/person/person.py +0 -29
  435. autobyteus/person/role.py +0 -14
  436. autobyteus/rpc/__init__.py +0 -73
  437. autobyteus/rpc/client/__init__.py +0 -17
  438. autobyteus/rpc/client/abstract_client_connection.py +0 -124
  439. autobyteus/rpc/client/client_connection_manager.py +0 -153
  440. autobyteus/rpc/client/sse_client_connection.py +0 -306
  441. autobyteus/rpc/client/stdio_client_connection.py +0 -280
  442. autobyteus/rpc/config/__init__.py +0 -13
  443. autobyteus/rpc/config/agent_server_config.py +0 -153
  444. autobyteus/rpc/config/agent_server_registry.py +0 -152
  445. autobyteus/rpc/hosting.py +0 -244
  446. autobyteus/rpc/protocol.py +0 -244
  447. autobyteus/rpc/server/__init__.py +0 -20
  448. autobyteus/rpc/server/agent_server_endpoint.py +0 -181
  449. autobyteus/rpc/server/base_method_handler.py +0 -40
  450. autobyteus/rpc/server/method_handlers.py +0 -259
  451. autobyteus/rpc/server/sse_server_handler.py +0 -182
  452. autobyteus/rpc/server/stdio_server_handler.py +0 -151
  453. autobyteus/rpc/server_main.py +0 -198
  454. autobyteus/rpc/transport_type.py +0 -13
  455. autobyteus/tools/bash/__init__.py +0 -2
  456. autobyteus/tools/bash/bash_executor.py +0 -100
  457. autobyteus/tools/browser/__init__.py +0 -2
  458. autobyteus/tools/browser/session_aware/__init__.py +0 -0
  459. autobyteus/tools/browser/session_aware/browser_session_aware_navigate_to.py +0 -75
  460. autobyteus/tools/browser/session_aware/browser_session_aware_tool.py +0 -30
  461. autobyteus/tools/browser/session_aware/browser_session_aware_web_element_trigger.py +0 -154
  462. autobyteus/tools/browser/session_aware/browser_session_aware_webpage_reader.py +0 -89
  463. autobyteus/tools/browser/session_aware/browser_session_aware_webpage_screenshot_taker.py +0 -107
  464. autobyteus/tools/browser/session_aware/factory/__init__.py +0 -0
  465. autobyteus/tools/browser/session_aware/factory/browser_session_aware_web_element_trigger_factory.py +0 -14
  466. autobyteus/tools/browser/session_aware/factory/browser_session_aware_webpage_reader_factory.py +0 -26
  467. autobyteus/tools/browser/session_aware/factory/browser_session_aware_webpage_screenshot_taker_factory.py +0 -14
  468. autobyteus/tools/browser/session_aware/shared_browser_session.py +0 -11
  469. autobyteus/tools/browser/session_aware/shared_browser_session_manager.py +0 -25
  470. autobyteus/tools/browser/session_aware/web_element_action.py +0 -20
  471. autobyteus/tools/browser/standalone/__init__.py +0 -6
  472. autobyteus/tools/browser/standalone/factory/__init__.py +0 -0
  473. autobyteus/tools/browser/standalone/factory/webpage_reader_factory.py +0 -25
  474. autobyteus/tools/browser/standalone/factory/webpage_screenshot_taker_factory.py +0 -14
  475. autobyteus/tools/browser/standalone/navigate_to.py +0 -80
  476. autobyteus/tools/browser/standalone/web_page_pdf_generator.py +0 -97
  477. autobyteus/tools/browser/standalone/webpage_image_downloader.py +0 -165
  478. autobyteus/tools/browser/standalone/webpage_reader.py +0 -101
  479. autobyteus/tools/browser/standalone/webpage_screenshot_taker.py +0 -101
  480. autobyteus/tools/file/file_editor.py +0 -200
  481. autobyteus/tools/google_search.py +0 -149
  482. autobyteus/tools/timer.py +0 -171
  483. autobyteus/tools/usage/parsers/__init__.py +0 -22
  484. autobyteus/tools/usage/parsers/_json_extractor.py +0 -99
  485. autobyteus/tools/usage/parsers/_string_decoders.py +0 -18
  486. autobyteus/tools/usage/parsers/anthropic_xml_tool_usage_parser.py +0 -10
  487. autobyteus/tools/usage/parsers/base_parser.py +0 -41
  488. autobyteus/tools/usage/parsers/default_json_tool_usage_parser.py +0 -83
  489. autobyteus/tools/usage/parsers/default_xml_tool_usage_parser.py +0 -316
  490. autobyteus/tools/usage/parsers/exceptions.py +0 -13
  491. autobyteus/tools/usage/parsers/gemini_json_tool_usage_parser.py +0 -77
  492. autobyteus/tools/usage/parsers/openai_json_tool_usage_parser.py +0 -149
  493. autobyteus/tools/usage/parsers/provider_aware_tool_usage_parser.py +0 -59
  494. autobyteus/tools/usage/registries/tool_usage_parser_registry.py +0 -62
  495. autobyteus/workflow/phases/__init__.py +0 -11
  496. autobyteus/workflow/phases/workflow_operational_phase.py +0 -19
  497. autobyteus/workflow/phases/workflow_phase_manager.py +0 -48
  498. autobyteus-1.2.0.dist-info/METADATA +0 -205
  499. autobyteus-1.2.0.dist-info/RECORD +0 -496
  500. examples/__init__.py +0 -1
  501. examples/agent_team/__init__.py +0 -1
  502. examples/discover_phase_transitions.py +0 -104
  503. examples/run_browser_agent.py +0 -262
  504. examples/run_google_slides_agent.py +0 -287
  505. examples/run_mcp_browser_client.py +0 -174
  506. examples/run_mcp_google_slides_client.py +0 -270
  507. examples/run_mcp_list_tools.py +0 -189
  508. examples/run_poem_writer.py +0 -284
  509. examples/run_sqlite_agent.py +0 -295
  510. /autobyteus/{person → skills}/__init__.py +0 -0
  511. /autobyteus/{person/examples → tools/skill}/__init__.py +0 -0
  512. {autobyteus-1.2.0.dist-info → autobyteus-1.2.3.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,328 @@
1
+ """
2
+ XmlPatchFileToolParsingState: Streams <tool name="patch_file"> blocks.
3
+
4
+ This state specializes the generic XmlToolParsingState to stream patch/diff content
5
+ and capture the path for display. Argument parsing is handled later by the
6
+ ToolInvocationAdapter.
7
+ """
8
+ from typing import TYPE_CHECKING, Optional
9
+
10
+ from .xml_tool_parsing_state import XmlToolParsingState
11
+ from ..events import SegmentType
12
+
13
+ if TYPE_CHECKING:
14
+ from ..parser_context import ParserContext
15
+
16
+
17
+ class XmlPatchFileToolParsingState(XmlToolParsingState):
18
+ """
19
+ Streams <tool name="patch_file"> tool calls.
20
+
21
+ This state operates similarly to XmlWriteFileToolParsingState but provides
22
+ a distinct type (PATCH_FILE) for unified diff content streaming.
23
+
24
+ Key differences from write_file:
25
+ - Content arg name: 'patch' instead of 'content'
26
+ - Sentinel markers: __START_PATCH__ / __END_PATCH__
27
+ - Segment type: PATCH_FILE
28
+ """
29
+
30
+ SEGMENT_TYPE = SegmentType.PATCH_FILE
31
+ START_CONTENT_MARKER = "__START_PATCH__"
32
+ END_CONTENT_MARKER = "__END_PATCH__"
33
+ CONTENT_ARG_CLOSE_TAG = "</arg>"
34
+
35
+ def __init__(self, context: "ParserContext", opening_tag: str):
36
+ super().__init__(context, opening_tag)
37
+ if self._tool_name != "patch_file":
38
+ pass
39
+
40
+ # Internal state for streaming
41
+ self._found_content_start = False
42
+ self._content_buffering = ""
43
+ self._captured_path: Optional[str] = None
44
+ self._defer_start = True # Defer emission until path is found
45
+ self._swallowing_remaining = False # Swallow closing tags
46
+ self._content_mode = "seek_marker"
47
+ self._content_seek_buffer = ""
48
+ self._marker_tail = ""
49
+
50
+ def run(self) -> None:
51
+ """
52
+ Custom run loop to stream ONLY the patch argument content.
53
+ """
54
+ from .text_state import TextState
55
+
56
+ if self._swallowing_remaining:
57
+ self._handle_swallowing()
58
+ return
59
+
60
+ # Note: We do NOT emit start immediately anymore.
61
+
62
+ if not self.context.has_more_chars():
63
+ return
64
+
65
+ chunk = self.context.consume_remaining()
66
+
67
+ if not self._found_content_start:
68
+ self._content_buffering += chunk
69
+
70
+ import re
71
+
72
+ # 1. Try to find path if missing
73
+ if not self._captured_path:
74
+ path_match = re.search(r'<arg\s+name=["\']path["\']>([^<]+)</arg>', self._content_buffering, re.IGNORECASE)
75
+ if path_match:
76
+ self._captured_path = path_match.group(1).strip()
77
+ # Now we have path, we can emit start if we were waiting for it
78
+ if self._defer_start and not self._segment_started:
79
+ # Construct metadata with path
80
+ meta = self._get_start_metadata()
81
+ meta["path"] = self._captured_path
82
+ self.context.emit_segment_start(self.SEGMENT_TYPE, **meta)
83
+ self._segment_started = True
84
+ self._defer_start = False
85
+
86
+ # 2. Look for patch content start (note: arg name is 'patch', not 'content')
87
+ match = re.search(r'<arg\s+name=["\']patch["\']>', self._content_buffering, re.IGNORECASE)
88
+
89
+ if match:
90
+ self._found_content_start = True
91
+ end_of_tag = match.end()
92
+
93
+ # If we still haven't emitted start (e.g. no path found but content started), emit now without path
94
+ if not self._segment_started:
95
+ self.context.emit_segment_start(self.SEGMENT_TYPE, **self._get_start_metadata())
96
+ self._segment_started = True
97
+
98
+ # Update path in metadata if we found it late (redundant but safe)
99
+ if self._captured_path:
100
+ self.context.update_current_segment_metadata(path=self._captured_path)
101
+
102
+ real_content = self._content_buffering[end_of_tag:]
103
+ self._content_buffering = ""
104
+ self._content_mode = "seek_marker"
105
+ self._content_seek_buffer = ""
106
+ self._marker_tail = ""
107
+ self._tail = ""
108
+ self._process_content_chunk(real_content)
109
+ else:
110
+ # If closing tool and still no content
111
+ if "</tool>" in self._content_buffering:
112
+ # If start never happened, force it
113
+ if not self._segment_started:
114
+ self.context.emit_segment_start(self.SEGMENT_TYPE, **self._get_start_metadata())
115
+ self._segment_started = True
116
+
117
+ self._on_segment_complete()
118
+ self.context.emit_segment_end()
119
+ self.context.transition_to(TextState(self.context))
120
+ else:
121
+ self._process_content_chunk(chunk)
122
+
123
+ def _process_content_chunk(self, chunk: str) -> None:
124
+ """Process content chunk, supporting optional content markers."""
125
+ if not chunk:
126
+ return
127
+
128
+ if self._content_mode == "marker":
129
+ self._process_marker_content(chunk)
130
+ return
131
+
132
+ if self._content_mode == "default":
133
+ self._process_default_content(chunk)
134
+ return
135
+
136
+ self._process_seek_marker_content(chunk)
137
+
138
+ def _process_seek_marker_content(self, chunk: str) -> None:
139
+ """Seek __START_PATCH__ before committing to default parsing."""
140
+ self._content_seek_buffer += chunk
141
+
142
+ start_idx = self._content_seek_buffer.find(self.START_CONTENT_MARKER)
143
+ if start_idx != -1:
144
+ after_start = self._content_seek_buffer[start_idx + len(self.START_CONTENT_MARKER):]
145
+ # Strip leading newline after marker to avoid empty first line
146
+ if after_start.startswith("\n"):
147
+ after_start = after_start[1:]
148
+ self._content_seek_buffer = ""
149
+ self._content_mode = "marker"
150
+ self._marker_tail = ""
151
+ self._tail = ""
152
+ if after_start:
153
+ self._process_marker_content(after_start)
154
+ return
155
+
156
+ closing_idx = self._content_seek_buffer.find(self.CONTENT_ARG_CLOSE_TAG)
157
+ if closing_idx != -1:
158
+ buffered = self._content_seek_buffer
159
+ self._content_seek_buffer = ""
160
+ self._content_mode = "default"
161
+ self._tail = ""
162
+ self._process_default_content(buffered)
163
+ return
164
+
165
+ stripped = self._content_seek_buffer.lstrip()
166
+ if stripped and not self.START_CONTENT_MARKER.startswith(stripped):
167
+ buffered = self._content_seek_buffer
168
+ self._content_seek_buffer = ""
169
+ self._content_mode = "default"
170
+ self._tail = ""
171
+ self._process_default_content(buffered)
172
+
173
+ def _process_default_content(self, chunk: str) -> None:
174
+ """Process content chunk, stripping closing tags."""
175
+ closing_tag = self.CONTENT_ARG_CLOSE_TAG
176
+ combined = self._tail + chunk
177
+
178
+ idx = combined.find(closing_tag)
179
+
180
+ if idx != -1:
181
+ actual_content = combined[:idx]
182
+ if actual_content:
183
+ self.context.emit_segment_content(actual_content)
184
+
185
+ # We found the end of the content argument.
186
+ # Switch to swallowing mode to eat </arguments></tool>
187
+ self._tail = ""
188
+ remainder = combined[idx + len(closing_tag):]
189
+ self._content_buffering = remainder
190
+ self._swallowing_remaining = True
191
+
192
+ # Immediately try to finish if we have the closing tags
193
+ self._handle_swallowing()
194
+ return
195
+
196
+ holdback_len = len(closing_tag) - 1
197
+ if len(combined) > holdback_len:
198
+ safe = combined[:-holdback_len]
199
+ if safe:
200
+ self.context.emit_segment_content(safe)
201
+ self._tail = combined[-holdback_len:]
202
+ else:
203
+ self._tail = combined
204
+
205
+ def _process_marker_content(self, chunk: str) -> None:
206
+ """Process content chunk when inside __START_PATCH__/__END_PATCH__ markers.
207
+
208
+ The __END_PATCH__ sentinel is only valid if followed by optional whitespace
209
+ and then </arg>. This prevents false positives when patch content contains
210
+ the literal __END_PATCH__ string.
211
+ """
212
+ import re
213
+
214
+ combined = self._marker_tail + chunk
215
+ end_marker = self.END_CONTENT_MARKER
216
+ closing_tag = self.CONTENT_ARG_CLOSE_TAG
217
+
218
+ # Priority 1: Check for the explicit end marker WITH lookahead validation
219
+ search_start = 0
220
+ while True:
221
+ idx = combined.find(end_marker, search_start)
222
+ if idx == -1:
223
+ break
224
+
225
+ remainder_after_marker = combined[idx + len(end_marker):]
226
+
227
+ # Validate: must be followed by whitespace* + </arg>
228
+ if re.match(r'^\s*</arg>', remainder_after_marker):
229
+ # Valid sentinel - emit content and transition
230
+ actual_content = combined[:idx]
231
+ if actual_content:
232
+ self.context.emit_segment_content(actual_content)
233
+
234
+ self._marker_tail = ""
235
+ remainder = combined[idx + len(end_marker):]
236
+ self._content_buffering = remainder
237
+ self._swallowing_remaining = True
238
+ self._handle_swallowing()
239
+ return
240
+ elif remainder_after_marker.strip() == "":
241
+ # Indeterminate - need more data
242
+ # Hold back from idx onwards
243
+ if idx > 0:
244
+ safe_content = combined[:idx]
245
+ if safe_content:
246
+ self.context.emit_segment_content(safe_content)
247
+ self._marker_tail = combined[idx:]
248
+ else:
249
+ self._marker_tail = combined
250
+ return
251
+ else:
252
+ # False positive
253
+ search_start = idx + len(end_marker)
254
+
255
+ # Priority 2: Check for closing arg tag as fallback (missing sentinel case)
256
+ idx_close = combined.find(closing_tag)
257
+ if idx_close != -1:
258
+ remainder_after_close = combined[idx_close + len(closing_tag):]
259
+
260
+ # Check if followed by standard XML closure (ignoring whitespace)
261
+ is_valid_closure = False
262
+ if re.match(r'^\s*(?:</arguments>|</tool>)', remainder_after_close):
263
+ is_valid_closure = True
264
+
265
+ # If we have indeterminate whitespace, we must hold back to be sure
266
+ elif remainder_after_close.strip() == "":
267
+ self._marker_tail = combined
268
+ return
269
+
270
+ if is_valid_closure:
271
+ actual_content = combined[:idx_close]
272
+
273
+ # Remove trailing newline for clean file content
274
+ if re.search(r'\n\s*$', actual_content):
275
+ actual_content = re.sub(r'\n\s*$', '', actual_content)
276
+
277
+ if actual_content:
278
+ self.context.emit_segment_content(actual_content)
279
+
280
+ self._marker_tail = ""
281
+ remainder = combined[idx_close + len(closing_tag):]
282
+ self._content_buffering = remainder
283
+ self._swallowing_remaining = True
284
+ self._handle_swallowing()
285
+ return
286
+
287
+ # Holdback logic - hold back enough to detect EITHER marker OR closing_tag + context
288
+ # __END_PATCH__ is shorter than __END_CONTENT__ but still needs buffer
289
+ max_holdback = 35
290
+
291
+ if len(combined) > max_holdback:
292
+ safe = combined[:-max_holdback]
293
+ if safe:
294
+ self.context.emit_segment_content(safe)
295
+ self._marker_tail = combined[-max_holdback:]
296
+ else:
297
+ self._marker_tail = combined
298
+
299
+ def _handle_swallowing(self) -> None:
300
+ """Consume stream until </tool> is found."""
301
+ from .text_state import TextState
302
+
303
+ # Add any new data to buffer
304
+ self._content_buffering += self.context.consume_remaining()
305
+
306
+ closing_tag = "</tool>"
307
+ idx = self._content_buffering.find(closing_tag)
308
+
309
+ if idx != -1:
310
+ # We found the end!
311
+ # Anything after </tool> belongs to the next state (TextState)
312
+ remainder = self._content_buffering[idx + len(closing_tag):]
313
+
314
+ self._on_segment_complete()
315
+ self.context.emit_segment_end()
316
+ if remainder:
317
+ # Rewind so the next state can parse the remainder (e.g., another tool tag).
318
+ self.context.rewind_by(len(remainder))
319
+ self.context.transition_to(TextState(self.context))
320
+ else:
321
+ # Nothing yet, keep swallowing
322
+ holdback_len = len(closing_tag) - 1
323
+ if len(self._content_buffering) > holdback_len:
324
+ # Discard safe prefix
325
+ self._content_buffering = self._content_buffering[-holdback_len:]
326
+
327
+ def _on_segment_complete(self) -> None:
328
+ return None
@@ -0,0 +1,129 @@
1
+ """
2
+ XmlRunBashToolParsingState: Streams <tool name="run_bash"> blocks.
3
+
4
+ This state specializes the generic XmlToolParsingState to stream the command
5
+ content without parsing arguments. Argument parsing is handled later by the
6
+ ToolInvocationAdapter.
7
+ """
8
+ from typing import TYPE_CHECKING
9
+
10
+ from .xml_tool_parsing_state import XmlToolParsingState
11
+ from ..events import SegmentType
12
+
13
+ if TYPE_CHECKING:
14
+ from ..parser_context import ParserContext
15
+
16
+
17
+ class XmlRunBashToolParsingState(XmlToolParsingState):
18
+ """
19
+ Parses <tool name="run_bash"> tool calls.
20
+
21
+ This state operates identically to XmlToolParsingState but provides
22
+ a distinct type (RUN_BASH) and specialized metadata handling if needed.
23
+ """
24
+
25
+ SEGMENT_TYPE = SegmentType.RUN_BASH
26
+
27
+ def __init__(self, context: "ParserContext", opening_tag: str):
28
+ super().__init__(context, opening_tag)
29
+ if self._tool_name != "run_bash":
30
+ pass
31
+
32
+ self._found_content_start = False
33
+ self._content_buffering = ""
34
+ self._swallowing_remaining = False
35
+
36
+ def run(self) -> None:
37
+ """
38
+ Custom run loop to stream ONLY the command argument.
39
+ """
40
+ from .text_state import TextState
41
+
42
+ if self._swallowing_remaining:
43
+ self._handle_swallowing()
44
+ return
45
+
46
+ if not self._segment_started:
47
+ self.context.emit_segment_start(self.SEGMENT_TYPE, **self._get_start_metadata())
48
+ self._segment_started = True
49
+
50
+ if not self.context.has_more_chars():
51
+ return
52
+
53
+ chunk = self.context.consume_remaining()
54
+
55
+ if not self._found_content_start:
56
+ self._content_buffering += chunk
57
+
58
+ import re
59
+ # Look for command start
60
+ match = re.search(r'<arg\s+name=["\']command["\']>', self._content_buffering, re.IGNORECASE)
61
+
62
+ if match:
63
+ self._found_content_start = True
64
+ end_of_tag = match.end()
65
+
66
+ real_content = self._content_buffering[end_of_tag:]
67
+ self._content_buffering = ""
68
+ self._process_content_chunk(real_content)
69
+ else:
70
+ if "</tool>" in self._content_buffering:
71
+ self._on_segment_complete()
72
+ self.context.emit_segment_end()
73
+ self.context.transition_to(TextState(self.context))
74
+ else:
75
+ self._process_content_chunk(chunk)
76
+
77
+ def _process_content_chunk(self, chunk: str) -> None:
78
+ """Process content chunk, stripping closing tags."""
79
+
80
+ closing_tag = "</arg>"
81
+ combined = self._tail + chunk
82
+
83
+ idx = combined.find(closing_tag)
84
+ if idx != -1:
85
+ actual_content = combined[:idx]
86
+ if actual_content:
87
+ self.context.emit_segment_content(actual_content)
88
+
89
+ self._tail = ""
90
+ remainder = combined[idx + len(closing_tag):]
91
+ self._content_buffering = remainder
92
+ self._swallowing_remaining = True
93
+
94
+ self._handle_swallowing()
95
+ return
96
+
97
+ holdback_len = len(closing_tag) - 1
98
+ if len(combined) > holdback_len:
99
+ safe = combined[:-holdback_len]
100
+ self.context.emit_segment_content(safe)
101
+ self._tail = combined[-holdback_len:]
102
+ else:
103
+ self._tail = combined
104
+
105
+ def _handle_swallowing(self) -> None:
106
+ """Consume stream until </tool> is found."""
107
+ from .text_state import TextState
108
+
109
+ self._content_buffering += self.context.consume_remaining()
110
+
111
+ closing_tag = "</tool>"
112
+ idx = self._content_buffering.find(closing_tag)
113
+
114
+ if idx != -1:
115
+ remainder = self._content_buffering[idx + len(closing_tag):]
116
+
117
+ self._on_segment_complete()
118
+ self.context.emit_segment_end()
119
+ if remainder:
120
+ # Rewind so the next state can parse the remainder (e.g., another tool tag).
121
+ self.context.rewind_by(len(remainder))
122
+ self.context.transition_to(TextState(self.context))
123
+ else:
124
+ holdback_len = len(closing_tag) - 1
125
+ if len(self._content_buffering) > holdback_len:
126
+ self._content_buffering = self._content_buffering[-holdback_len:]
127
+
128
+ def _on_segment_complete(self) -> None:
129
+ return None
@@ -0,0 +1,151 @@
1
+ """
2
+ XmlTagInitializationState: Analyzes potential XML tags after a '<' is detected.
3
+
4
+ This state buffers characters to identify special tags like <tool, <write_file,
5
+ <run_bash and transitions to the appropriate specialized state.
6
+
7
+ UNIFORM HANDOFF: All content states receive the complete opening_tag and handle
8
+ their own initialization consistently.
9
+ """
10
+ from typing import TYPE_CHECKING
11
+
12
+ from .base_state import BaseState
13
+ from ..events import SegmentType
14
+
15
+ if TYPE_CHECKING:
16
+ from ..parser_context import ParserContext
17
+
18
+
19
+ class XmlTagInitializationState(BaseState):
20
+ """
21
+ Analyzes a potential XML tag to determine the correct specialized state.
22
+
23
+ This state is entered when a '<' is detected. It buffers characters
24
+ to identify tags like <tool, <write_file, <run_bash.
25
+
26
+ If no known tag is detected, the buffered content is emitted as text.
27
+
28
+ UNIFORM HANDOFF PATTERN:
29
+ All content-parsing states receive (context, opening_tag) and handle
30
+ their own buffer initialization consistently.
31
+ """
32
+
33
+ # Known tag prefixes (lowercase for case-insensitive matching)
34
+ POSSIBLE_WRITE_FILE = "<write_file"
35
+ POSSIBLE_RUN_BASH = "<run_bash"
36
+ POSSIBLE_TOOL = "<tool"
37
+
38
+ def __init__(self, context: "ParserContext"):
39
+ super().__init__(context)
40
+ # Consume the '<' that triggered this state
41
+ self.context.advance()
42
+ self._tag_buffer = "<"
43
+
44
+ def run(self) -> None:
45
+ """
46
+ Buffer characters and identify the tag type.
47
+
48
+ Transitions to specialized states or reverts to text if unknown.
49
+ """
50
+ from .text_state import TextState
51
+ from .custom_xml_tag_write_file_parsing_state import CustomXmlTagWriteFileParsingState
52
+ from .custom_xml_tag_run_bash_parsing_state import CustomXmlTagRunBashParsingState
53
+ from .xml_tool_parsing_state import XmlToolParsingState
54
+ from .xml_write_file_tool_parsing_state import XmlWriteFileToolParsingState
55
+ from .xml_run_bash_tool_parsing_state import XmlRunBashToolParsingState
56
+
57
+ if not self.context.has_more_chars():
58
+ return
59
+
60
+ start_pos = self.context.get_position()
61
+ end_idx = self.context.find(">", start_pos)
62
+
63
+ if end_idx == -1:
64
+ self._tag_buffer += self.context.consume_remaining()
65
+
66
+ lower_buffer = self._tag_buffer.lower()
67
+ could_be_write_file = (
68
+ self.POSSIBLE_WRITE_FILE.startswith(lower_buffer) or
69
+ lower_buffer.startswith(self.POSSIBLE_WRITE_FILE)
70
+ )
71
+ could_be_run_bash = (
72
+ self.POSSIBLE_RUN_BASH.startswith(lower_buffer) or
73
+ lower_buffer.startswith(self.POSSIBLE_RUN_BASH)
74
+ )
75
+ could_be_tool = (
76
+ self.POSSIBLE_TOOL.startswith(lower_buffer) or
77
+ lower_buffer.startswith(self.POSSIBLE_TOOL)
78
+ )
79
+
80
+ if not (could_be_write_file or could_be_run_bash or could_be_tool):
81
+ self.context.append_text_segment(self._tag_buffer)
82
+ self.context.transition_to(TextState(self.context))
83
+ return
84
+
85
+ self._tag_buffer += self.context.consume(end_idx - start_pos + 1)
86
+ lower_buffer = self._tag_buffer.lower()
87
+
88
+ # Handle legacy <write_file> tag
89
+ if lower_buffer.startswith(self.POSSIBLE_WRITE_FILE):
90
+ if self.context.get_current_segment_type() == SegmentType.TEXT:
91
+ self.context.emit_segment_end()
92
+ self.context.transition_to(
93
+ CustomXmlTagWriteFileParsingState(self.context, self._tag_buffer)
94
+ )
95
+ return
96
+
97
+ if lower_buffer.startswith(self.POSSIBLE_RUN_BASH):
98
+ if self.context.get_current_segment_type() == SegmentType.TEXT:
99
+ self.context.emit_segment_end()
100
+ self.context.transition_to(
101
+ CustomXmlTagRunBashParsingState(self.context, self._tag_buffer)
102
+ )
103
+ return
104
+
105
+ if lower_buffer.startswith(self.POSSIBLE_TOOL):
106
+ if self.context.parse_tool_calls:
107
+ if self.context.get_current_segment_type() == SegmentType.TEXT:
108
+ self.context.emit_segment_end()
109
+
110
+ # Extract tool name
111
+ import re
112
+ name_match = re.search(r'name\s*=\s*["\']([^"\']+)["\']', self._tag_buffer, re.IGNORECASE)
113
+
114
+ if name_match:
115
+ tool_name = name_match.group(1).lower()
116
+
117
+ # --- Registry Lookup ---
118
+ from ..xml_tool_parsing_state_registry import XmlToolParsingStateRegistry
119
+ registry = XmlToolParsingStateRegistry()
120
+
121
+ # Dispatch
122
+ state_class = registry.get_state_for_tool(tool_name)
123
+ if state_class:
124
+ self.context.transition_to(state_class(self.context, self._tag_buffer))
125
+ else:
126
+ # Fallback to generic tool state
127
+ self.context.transition_to(XmlToolParsingState(self.context, self._tag_buffer))
128
+ else:
129
+ # No name found, generic fallback
130
+ self.context.transition_to(XmlToolParsingState(self.context, self._tag_buffer))
131
+ else:
132
+ self.context.append_text_segment(self._tag_buffer)
133
+ self.context.transition_to(TextState(self.context))
134
+ return
135
+
136
+ self.context.append_text_segment(self._tag_buffer)
137
+ self.context.transition_to(TextState(self.context))
138
+
139
+ def finalize(self) -> None:
140
+ """
141
+ Called when stream ends while in this state.
142
+
143
+ Emit any buffered content as text.
144
+ """
145
+ from .text_state import TextState
146
+
147
+ if self._tag_buffer:
148
+ self.context.append_text_segment(self._tag_buffer)
149
+ self._tag_buffer = ""
150
+
151
+ self.context.transition_to(TextState(self.context))
@@ -0,0 +1,63 @@
1
+ """
2
+ XmlToolParsingState: Streams <tool name="...">...</tool> blocks.
3
+
4
+ This state handles tool call boundaries and content streaming. Tool arguments
5
+ are parsed later by the ToolInvocationAdapter.
6
+ """
7
+ import re
8
+ from typing import TYPE_CHECKING, Optional
9
+
10
+ from .delimited_content_state import DelimitedContentState
11
+ from ..events import SegmentType
12
+
13
+ if TYPE_CHECKING:
14
+ from ..parser_context import ParserContext
15
+
16
+
17
+ class XmlToolParsingState(DelimitedContentState):
18
+ """
19
+ Streams tool call blocks.
20
+
21
+ Expected format: <tool name="..."><arg>value</arg></tool>
22
+
23
+ Supports two argument formats:
24
+ 1. Wrapped: <arguments><arg1>value1</arg1></arguments>
25
+ 2. Direct: <arg1>value1</arg1><arg2>value2</arg2>
26
+
27
+ The state:
28
+ 1. Extracts tool name from the opening tag
29
+ 2. Emits SEGMENT_START with tool metadata
30
+ 3. Streams raw content for real-time display
31
+ 4. Emits SEGMENT_END when </tool> is found
32
+ """
33
+
34
+ # Pattern to extract tool name
35
+ NAME_PATTERN = re.compile(r'name\s*=\s*["\']([^"\']+)["\']', re.IGNORECASE)
36
+ CLOSING_TAG = "</tool>"
37
+ SEGMENT_TYPE = SegmentType.TOOL_CALL
38
+ def __init__(self, context: "ParserContext", opening_tag: str):
39
+ """
40
+ Initialize the tool parsing state.
41
+
42
+ Args:
43
+ context: The parser context.
44
+ opening_tag: The complete opening tag (e.g., '<tool name="read_file">').
45
+ """
46
+ super().__init__(context, opening_tag)
47
+ self._tool_name: Optional[str] = None
48
+
49
+ # Extract tool name from opening tag
50
+ match = self.NAME_PATTERN.search(opening_tag)
51
+ if match:
52
+ self._tool_name = match.group(1)
53
+
54
+ def _can_start_segment(self) -> bool:
55
+ return self._tool_name is not None
56
+
57
+ def _get_start_metadata(self) -> dict:
58
+ return {"tool_name": self._tool_name} if self._tool_name else {}
59
+
60
+ def _on_segment_complete(self) -> None:
61
+ return None
62
+
63
+ # finalize inherited from DelimitedContentState