"""Typed event dataclasses for SSE stream events. The client parses raw SSE frames into these types. Consumers iterate over them via ``async for event in stream``. """ from __future__ import annotations from dataclasses import dataclass, field from ._types import ErrorInfo, Response # ── Native tool type constants ─────────────────────────── NATIVE_TOOL_TYPES: frozenset[str] = frozenset( { "web_search_call", "file_search_call", "code_interpreter_call", "computer_call", "image_generation_call", "mcp_call", "mcp_list_tools", } ) # JSON-RPC method name MCP uses for elicitation requests. The # server's ``response.elicitation_request`` SSE event carries this # verbatim under ``method`` so MCP-aware consumers can route on # the same name they already recognize. MCP_ELICITATION_METHOD = "elicitation/create" # ── Response lifecycle events ──────────────────────────── @dataclass class ResponseCreated: """``response.created`` — always first (sequence 0).""" response: Response @dataclass class ResponseQueued: """``response.queued`` — only when ``background=True``.""" response: Response @dataclass class ResponseInProgress: """``response.in_progress`` — execution started.""" response: Response @dataclass class ResponseCompleted: """``response.completed`` — agent finished successfully.""" response: Response @dataclass class ResponseFailed: """``response.failed`` — unrecoverable error.""" response: Response @dataclass class ResponseIncomplete: """``response.incomplete`` — stopped early.""" response: Response reason: str # "max_iterations", "execution_timeout", etc. @dataclass class ResponseCancelled: """``response.cancelled`` — cancelled via POST /cancel.""" response: Response # ── Text streaming ─────────────────────────────────────── @dataclass class TextDelta: """``response.output_text.delta`` — incremental text token.""" delta: str # ── Reasoning ──────────────────────────────────────────── @dataclass class ReasoningStarted: """``response.reasoning.started`` — reasoning block opened.""" @dataclass class ReasoningDelta: """``response.reasoning_text.delta`` — reasoning token.""" delta: str @dataclass class ReasoningSummaryDelta: """``response.reasoning_summary_text.delta`` — summary token.""" delta: str # ── Parsed output items ───────────────────────────────── @dataclass class ToolCall: """A tool call from ``output_item.done`` (type ``function_call``).""" name: str arguments: dict[str, object] call_id: str status: str # "completed", "action_required", "incomplete" agent_name: str # "coder" or "coder.researcher" @dataclass class ToolResult: """A tool result from ``output_item.done`` (type ``function_call_output``). ``arguments`` is optional because the OpenAI-compatible ``function_call_output`` item only requires ``call_id`` and ``output``. Omnigent producers may include it as a convenience copy of the originating ``function_call.arguments`` so result-only renderers can use call metadata (for example, rendering ``sys_os_edit`` as a diff). """ call_id: str output: str arguments: dict[str, object] = field(default_factory=dict) @dataclass class ElicitationRequest: """ A server-initiated elicitation, MCP shape. Parsed out of the ``response.elicitation_request`` SSE event; the event's ``params`` block matches MCP's ``ElicitRequestFormParams`` field-for-field, plus extras (``phase``, ``policy_name``, ``content_preview``) under MCP's ``extra="allow"`` config that today's only producer (the policy ASK flow) populates for renderer use. Consumers respond via ``POST /v1/sessions/{session_id}/events`` with ``type == "approval"`` and MCP-shape ``ElicitResult`` fields (``action`` + optional ``content``) in ``data``. The client handles the POST automatically when an ``on_elicitation_request`` hook is registered on :class:`StreamHooks`. :param elicitation_id: Server-assigned id. Used in the approval event payload, e.g. ``"elicit_abc123"``. :param message: Human-readable prompt the consumer should render to the user. For the policy ASK producer this is the combined reason string from deciding ASKing policies. :param requested_schema: A restricted subset of JSON Schema defining the structure of the expected response. Empty ``{}`` for binary approve/reject elicitations (the verdict is in the consumer's ``action``). :param mode: MCP elicitation mode — ``"form"`` (inline) or ``"url"`` (standalone approval page). e.g. ``"url"``. :param phase: Producer-supplied extra (policy ASK only): which enforcement point produced the ASK — one of ``"input"``, ``"tool_call"``, ``"tool_result"``, ``"output"``. Empty string when the elicitation came from a producer that doesn't populate this extra. :param policy_name: Producer-supplied extra (policy ASK only): name of the deciding (first-in-YAML-order) ASKing policy, e.g. ``"approve_web_search"``. Empty string when not applicable. :param content_preview: Producer-supplied extra (policy ASK only): truncated snapshot of the gated content. Safe to display verbatim. Empty string when not applicable. :param target_session_id: Session whose resolve endpoint owns this elicitation, e.g. ``"conv_child123"``. Set when a sub-agent's prompt was mirrored into an ancestor stream so the consumer can route the verdict back to the child that parked on it. ``None`` means resolve against the session the event arrived on. """ elicitation_id: str message: str requested_schema: dict[str, object] mode: str phase: str policy_name: str content_preview: str url: str | None = None target_session_id: str | None = None @dataclass class NativeToolCall: """A provider-native tool output (web_search, mcp, etc.).""" tool_type: str # e.g. "web_search_call" data: dict[str, object] @dataclass class MessageDone: """The final assistant message from ``output_item.done`` (type ``message``).""" content: list[dict[str, object]] = field(default_factory=list) # ── File output ────────────────────────────────────────── @dataclass class OutputFileDone: """``response.output_file.done`` — file artifact produced.""" file_id: str filename: str | None = None content_type: str | None = None # ── Error and retry ────────────────────────────────────── @dataclass class RetryEvent: """``response.retry`` — a retryable failure, will retry.""" source: str # "llm" or "tool" tool_name: str | None attempt: int max_attempts: int delay_seconds: float error: ErrorInfo @dataclass class ErrorEvent: """``response.error`` — an error during execution.""" source: str # "llm" or "tool" tool_name: str | None error: ErrorInfo # ── Compaction ─────────────────────────────────────────── @dataclass class CompactionInProgress: """``response.compaction.in_progress`` — server started compacting.""" @dataclass class CompactionCompleted: """``response.compaction.completed`` — compaction finished successfully.""" @dataclass class CompactionFailed: """``response.compaction.failed`` — compaction failed; history unchanged.""" # ── Async client-tool cancel (Phase 5) ─────────────────── @dataclass class ClientTaskCancel: """ ``response.client_task.cancel`` — server-to-client cancel notification for async client-tool dispatches. Emitted when an async client tool task (``kind="client_tool"``) was cancelled mid-flight, either via direct ``sys_cancel_task`` or via parent-cancel propagation. The SDK should cancel the matching local ``asyncio.Task`` running the tool body. The body's eventual PATCH back is a no-op (G3 first-write-wins), so the cancel is best-effort from the SDK's perspective — the server has already decided the task is cancelled. :param task_id: The server-issued client-tool task id from the original ``function_call_output`` handle, e.g. ``"resp_async_xyz"``. :param call_id: The synthesized ``function_call.call_id`` the SDK saw on the action_required event for this dispatch, e.g. ``"call_async_b2c4..."``. Populated by the server from ``pending_tool_calls`` so the SDK can look up the local ``asyncio.Task`` it spawned. ``None`` on legacy emissions where the lookup wasn't done; the SDK falls back to no-op when both fields can't be matched to a tracked task. """ task_id: str call_id: str | None = None # ── Union type for all events ──────────────────────────── StreamEvent = ( ResponseCreated | ResponseQueued | ResponseInProgress | ResponseCompleted | ResponseFailed | ResponseIncomplete | ResponseCancelled | TextDelta | ReasoningStarted | ReasoningDelta | ReasoningSummaryDelta | ToolCall | ToolResult | NativeToolCall | MessageDone | OutputFileDone | RetryEvent | ErrorEvent | CompactionInProgress | CompactionCompleted | CompactionFailed | ClientTaskCancel | ElicitationRequest )