defmodule Anthropic.Event do @moduledoc """ Parses raw Anthropic SSE event maps into typed event structs. Each event arriving over the stream is a JSON-decoded map with a `"type"` key. `parse/1` dispatches on that key and returns the corresponding struct from the `Anthropic.Event.*` namespace, or `:skip` for events that carry no useful data (e.g. `ping`). """ alias Anthropic.Event.ContentBlockDelta alias Anthropic.Event.ContentBlockStart alias Anthropic.Event.ContentBlockStop alias Anthropic.Event.MessageDelta alias Anthropic.Event.MessageStart alias Anthropic.Event.MessageStop @type parsed_event :: Anthropic.Event.MessageStart.t() | Anthropic.Event.ContentBlockStart.t() | Anthropic.Event.ContentBlockDelta.t() | Anthropic.Event.ContentBlockStop.t() | Anthropic.Event.MessageDelta.t() | Anthropic.Event.MessageStop.t() @doc """ Parses a raw SSE event map into a typed struct. Returns `:skip` for `ping` events and any unrecognised event types. """ @spec parse(map()) :: parsed_event() | :skip def parse(%{"type" => "message_start", "message" => msg}) do %MessageStart{id: msg["id"], usage: msg["usage"]} end def parse(%{"type" => "content_block_start", "index" => idx, "content_block" => cb}) do %ContentBlockStart{index: idx, content_block: parse_content_block(cb)} end def parse(%{"type" => "content_block_delta", "index" => idx, "delta" => delta}) do %ContentBlockDelta{index: idx, delta: parse_delta(delta)} end def parse(%{"type" => "content_block_stop", "index" => idx}) do %ContentBlockStop{index: idx} end def parse(%{"type" => "message_delta", "delta" => delta} = event) do %MessageDelta{ stop_reason: parse_stop_reason(delta["stop_reason"]), usage: event["usage"] || delta["usage"] } end def parse(%{"type" => "message_stop"}) do %MessageStop{} end def parse(%{"type" => "ping"}), do: :skip def parse(_other), do: :skip defp parse_content_block(%{"type" => "text"} = cb) do %{type: :text, text: cb["text"]} end defp parse_content_block(%{"type" => "tool_use"} = cb) do %{type: :tool_use, id: cb["id"], name: cb["name"]} end defp parse_content_block(cb), do: cb defp parse_delta(%{"type" => "text_delta"} = d), do: %{type: :text_delta, text: d["text"]} defp parse_delta(%{"type" => "input_json_delta"} = d), do: %{type: :input_json_delta, partial_json: d["partial_json"]} defp parse_delta(d), do: d defp parse_stop_reason("end_turn"), do: :end_turn defp parse_stop_reason("tool_use"), do: :tool_use defp parse_stop_reason(other), do: other end