""" StreamEventEmitter - standardized event format. All events contain a type and associated data dict. """ from dataclasses import dataclass from typing import Any STREAM_PROTOCOL_CAPABILITIES = frozenset( { "complete_tool_call_v1", "correlated_tool_call_id_v1", "final_invalid_tool_call_v1", } ) @dataclass class StreamEvent: """Unified stream event.""" type: str data: dict[str, Any] class StreamEventEmitter: """Stream event emitter - creates standardized event dicts.""" @staticmethod def thinking(content: str, thinking_id: int = 0) -> StreamEvent: """Thinking content event.""" return StreamEvent( "thinking", {"type": "thinking", "content": content, "id": thinking_id} ) @staticmethod def reasoning_summary(summary: str) -> StreamEvent: """Provider-declared user-visible reasoning summary.""" return StreamEvent( "reasoning_summary", { "type": "reasoning_summary", "summary": summary, "visibility": "user_visible_summary", "source_kind": "provider_summary", }, ) @staticmethod def text(content: str) -> StreamEvent: """Text content event.""" return StreamEvent("text", {"type": "text", "content": content}) @staticmethod def tool_call(name: str, args: dict[str, Any], tool_id: str) -> StreamEvent: """Tool call event.""" return StreamEvent( "tool_call", {"type": "tool_call", "name": name, "args": args, "id": tool_id}, ) @staticmethod def tool_result( name: str, content: str, success: bool, tool_call_id: str, ) -> StreamEvent: """Tool result event.""" return StreamEvent( "tool_result", { "type": "tool_result", "name": name, "content": content, "success": success, "id": tool_call_id, }, ) @staticmethod def subagent_start( name: str, description: str, instance_id: str, tool_call_id: str ) -> StreamEvent: """Sub-agent delegation started.""" return StreamEvent( "subagent_start", { "type": "subagent_start", "name": name, "description": description, "instance_id": instance_id, "tool_call_id": tool_call_id, }, ) @staticmethod def subagent_tool_call( subagent: str, name: str, args: dict[str, Any], tool_id: str, instance_id: str, ) -> StreamEvent: """Tool call from inside a sub-agent.""" return StreamEvent( "subagent_tool_call", { "type": "subagent_tool_call", "subagent": subagent, "name": name, "args": args, "id": tool_id, "instance_id": instance_id, }, ) @staticmethod def subagent_tool_result( subagent: str, name: str, content: str, success: bool, tool_call_id: str, instance_id: str, ) -> StreamEvent: """Tool result from inside a sub-agent.""" return StreamEvent( "subagent_tool_result", { "type": "subagent_tool_result", "subagent": subagent, "name": name, "content": content, "success": success, "id": tool_call_id, "instance_id": instance_id, }, ) @staticmethod def subagent_text(subagent: str, content: str, instance_id: str) -> StreamEvent: """Text content from a sub-agent.""" return StreamEvent( "subagent_text", { "type": "subagent_text", "subagent": subagent, "content": content, "instance_id": instance_id, }, ) @staticmethod def subagent_end(name: str, instance_id: str) -> StreamEvent: """Sub-agent delegation completed.""" return StreamEvent( "subagent_end", {"type": "subagent_end", "name": name, "instance_id": instance_id}, ) @staticmethod def done(response: str = "") -> StreamEvent: """Done event.""" return StreamEvent( "done", {"type": "done", "content": response, "response": response} ) @staticmethod def usage_stats(input_tokens: int, output_tokens: int) -> StreamEvent: """Token usage statistics event.""" return StreamEvent( "usage_stats", { "type": "usage_stats", "input_tokens": input_tokens, "output_tokens": output_tokens, }, ) @staticmethod def interrupt( interrupt_id: str, action_requests: list, review_configs: list | None = None, ) -> StreamEvent: """Human-in-the-loop interrupt event.""" return StreamEvent( "interrupt", { "type": "interrupt", "interrupt_id": interrupt_id, "action_requests": action_requests, "review_configs": review_configs or [], }, ) @staticmethod def ask_user_interrupt( interrupt_id: str, questions: list, tool_call_id: str = "", ) -> StreamEvent: """Agent-initiated ask_user interrupt event.""" return StreamEvent( "ask_user", { "type": "ask_user", "interrupt_id": interrupt_id, "questions": questions, "tool_call_id": tool_call_id, }, ) @staticmethod def tool_selection(tools: list[str]) -> StreamEvent: """Tool selection event from LLMToolSelectorMiddleware.""" return StreamEvent("tool_selection", {"type": "tool_selection", "tools": tools}) @staticmethod def summarization(content: str) -> StreamEvent: """Context summarization event.""" return StreamEvent( "summarization", {"type": "summarization", "content": content} ) @staticmethod def summarization_start() -> StreamEvent: """Context summarization started.""" return StreamEvent( "summarization_start", {"type": "summarization_start"}, ) @staticmethod def error( message: str, *, code: str | None = None, recoverable: bool | None = None, details: dict[str, Any] | None = None, ) -> StreamEvent: """Error event.""" data: dict[str, Any] = {"type": "error", "message": message} if code is not None: data["code"] = code if recoverable is not None: data["recoverable"] = recoverable if details is not None: data["details"] = details return StreamEvent("error", data)