-module(anthropic@streaming@decoder). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/anthropic/streaming/decoder.gleam"). -export([decode_event/1]). -export_type([decode_error/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC( " JSON decoder for streaming events\n" "\n" " This module decodes JSON data from SSE events into typed StreamEvent values.\n" " It handles all Anthropic streaming event types including message_start,\n" " content_block_start, content_block_delta, content_block_stop,\n" " message_delta, message_stop, ping, and error events.\n" ). -type decode_error() :: {json_parse_error, binary()} | {unknown_event_type, binary()} | {missing_field, binary()} | {invalid_field_value, binary(), binary()}. -file("src/anthropic/streaming/decoder.gleam", 152). ?DOC(" Decoder for content block in content_block_start\n"). -spec content_block_start_decoder() -> gleam@dynamic@decode:decoder(anthropic@message:content_block()). content_block_start_decoder() -> gleam@dynamic@decode:field( <<"type"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Block_type) -> case Block_type of <<"text"/utf8>> -> gleam@dynamic@decode:optional_field( <<"text"/utf8>>, <<""/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Text) -> gleam@dynamic@decode:success({text_block, Text}) end ); <<"tool_use"/utf8>> -> gleam@dynamic@decode:field( <<"id"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Id) -> gleam@dynamic@decode:field( <<"name"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Name) -> gleam@dynamic@decode:success( {tool_use_block, Id, Name, <<""/utf8>>} ) end ) end ); _ -> gleam@dynamic@decode:success({text_block, <<""/utf8>>}) end end ). -file("src/anthropic/streaming/decoder.gleam", 195). ?DOC(" Decoder for delta content\n"). -spec delta_decoder() -> gleam@dynamic@decode:decoder(anthropic@streaming:content_block_delta()). delta_decoder() -> gleam@dynamic@decode:field( <<"type"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Delta_type) -> case Delta_type of <<"text_delta"/utf8>> -> gleam@dynamic@decode:field( <<"text"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Text) -> gleam@dynamic@decode:success( {text_content_delta, {text_delta, Text}} ) end ); <<"input_json_delta"/utf8>> -> gleam@dynamic@decode:field( <<"partial_json"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Partial_json) -> gleam@dynamic@decode:success( {input_json_content_delta, {input_json_delta, Partial_json}} ) end ); _ -> gleam@dynamic@decode:success( {text_content_delta, {text_delta, <<""/utf8>>}} ) end end ). -file("src/anthropic/streaming/decoder.gleam", 275). ?DOC(" Decoder for message delta usage\n"). -spec message_delta_usage_decoder() -> gleam@dynamic@decode:decoder(anthropic@streaming:message_delta_usage()). message_delta_usage_decoder() -> gleam@dynamic@decode:field( <<"output_tokens"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Output_tokens) -> gleam@dynamic@decode:success({message_delta_usage, Output_tokens}) end ). -file("src/anthropic/streaming/decoder.gleam", 295). ?DOC(" Decoder for error inner content\n"). -spec error_inner_decoder() -> gleam@dynamic@decode:decoder(anthropic@streaming:stream_error()). error_inner_decoder() -> gleam@dynamic@decode:field( <<"type"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Error_type) -> gleam@dynamic@decode:field( <<"message"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Message) -> gleam@dynamic@decode:success( {stream_error, Error_type, Message} ) end ) end ). -file("src/anthropic/streaming/decoder.gleam", 306). ?DOC(" Decoder for Usage\n"). -spec usage_decoder() -> gleam@dynamic@decode:decoder(anthropic@request:usage()). usage_decoder() -> gleam@dynamic@decode:field( <<"input_tokens"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Input_tokens) -> gleam@dynamic@decode:optional_field( <<"output_tokens"/utf8>>, 0, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Output_tokens) -> gleam@dynamic@decode:success( {usage, Input_tokens, Output_tokens} ) end ) end ). -file("src/anthropic/streaming/decoder.gleam", 320). ?DOC(" Parse role from string\n"). -spec parse_role(binary()) -> anthropic@message:role(). parse_role(Str) -> case Str of <<"assistant"/utf8>> -> assistant; _ -> assistant end. -file("src/anthropic/streaming/decoder.gleam", 107). ?DOC(" Decoder for MessageStart within the message field\n"). -spec message_start_decoder() -> gleam@dynamic@decode:decoder(anthropic@streaming:message_start()). message_start_decoder() -> gleam@dynamic@decode:field( <<"id"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Id) -> gleam@dynamic@decode:field( <<"type"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Message_type) -> gleam@dynamic@decode:field( <<"role"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Role_str) -> gleam@dynamic@decode:field( <<"model"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Model) -> gleam@dynamic@decode:field( <<"usage"/utf8>>, usage_decoder(), fun(Usage) -> Role = parse_role(Role_str), gleam@dynamic@decode:success( {message_start, Id, Message_type, Role, Model, Usage} ) end ) end ) end ) end ) end ). -file("src/anthropic/streaming/decoder.gleam", 328). ?DOC(" Parse stop reason from string\n"). -spec parse_stop_reason(binary()) -> gleam@option:option(anthropic@request:stop_reason()). parse_stop_reason(Str) -> case Str of <<"end_turn"/utf8>> -> {some, end_turn}; <<"max_tokens"/utf8>> -> {some, max_tokens}; <<"stop_sequence"/utf8>> -> {some, stop_sequence}; <<"tool_use"/utf8>> -> {some, tool_use}; _ -> none end. -file("src/anthropic/streaming/decoder.gleam", 256). ?DOC(" Decoder for message delta inner content\n"). -spec message_delta_inner_decoder() -> gleam@dynamic@decode:decoder(anthropic@streaming:message_delta()). message_delta_inner_decoder() -> gleam@dynamic@decode:optional_field( <<"stop_reason"/utf8>>, none, begin _pipe = {decoder, fun gleam@dynamic@decode:decode_string/1}, gleam@dynamic@decode:map(_pipe, fun(S) -> parse_stop_reason(S) end) end, fun(Stop_reason) -> gleam@dynamic@decode:optional_field( <<"stop_sequence"/utf8>>, none, begin _pipe@1 = {decoder, fun gleam@dynamic@decode:decode_string/1}, gleam@dynamic@decode:map( _pipe@1, fun(Field@0) -> {some, Field@0} end ) end, fun(Stop_sequence) -> gleam@dynamic@decode:success( {message_delta, Stop_reason, Stop_sequence} ) end ) end ). -file("src/anthropic/streaming/decoder.gleam", 339). ?DOC(" Format decode errors to string\n"). -spec format_errors(list(gleam@dynamic@decode:decode_error())) -> binary(). format_errors(Errors) -> _pipe = Errors, _pipe@1 = gleam@list:map( _pipe, fun(E) -> <<<<<<"expected "/utf8, (erlang:element(2, E))/binary>>/binary, ", got "/utf8>>/binary, (erlang:element(3, E))/binary>> end ), gleam@string:join(_pipe@1, <<"; "/utf8>>). -file("src/anthropic/streaming/decoder.gleam", 91). ?DOC(" Decode a message_start event\n"). -spec decode_message_start(gleam@dynamic:dynamic_()) -> {ok, anthropic@streaming:stream_event()} | {error, decode_error()}. decode_message_start(Json) -> Decoder = begin gleam@dynamic@decode:field( <<"message"/utf8>>, message_start_decoder(), fun(Message) -> gleam@dynamic@decode:success(Message) end ) end, case gleam@dynamic@decode:run(Json, Decoder) of {ok, Msg} -> {ok, {message_start_event, Msg}}; {error, Errors} -> {error, {json_parse_error, <<"Failed to decode message_start: "/utf8, (format_errors(Errors))/binary>>}} end. -file("src/anthropic/streaming/decoder.gleam", 126). ?DOC(" Decode a content_block_start event\n"). -spec decode_content_block_start(gleam@dynamic:dynamic_()) -> {ok, anthropic@streaming:stream_event()} | {error, decode_error()}. decode_content_block_start(Json) -> Decoder = begin gleam@dynamic@decode:field( <<"index"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Index) -> gleam@dynamic@decode:field( <<"content_block"/utf8>>, content_block_start_decoder(), fun(Content_block) -> gleam@dynamic@decode:success({Index, Content_block}) end ) end ) end, case gleam@dynamic@decode:run(Json, Decoder) of {ok, {Index@1, Block}} -> {ok, {content_block_start_event, {content_block_start, Index@1, Block}}}; {error, Errors} -> {error, {json_parse_error, <<"Failed to decode content_block_start: "/utf8, (format_errors(Errors))/binary>>}} end. -file("src/anthropic/streaming/decoder.gleam", 170). ?DOC(" Decode a content_block_delta event\n"). -spec decode_content_block_delta(gleam@dynamic:dynamic_()) -> {ok, anthropic@streaming:stream_event()} | {error, decode_error()}. decode_content_block_delta(Json) -> Decoder = begin gleam@dynamic@decode:field( <<"index"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Index) -> gleam@dynamic@decode:field( <<"delta"/utf8>>, delta_decoder(), fun(Delta) -> gleam@dynamic@decode:success({Index, Delta}) end ) end ) end, case gleam@dynamic@decode:run(Json, Decoder) of {ok, {Index@1, Delta@1}} -> {ok, {content_block_delta_event_variant, {content_block_delta_event, Index@1, Delta@1}}}; {error, Errors} -> {error, {json_parse_error, <<"Failed to decode content_block_delta: "/utf8, (format_errors(Errors))/binary>>}} end. -file("src/anthropic/streaming/decoder.gleam", 214). ?DOC(" Decode a content_block_stop event\n"). -spec decode_content_block_stop(gleam@dynamic:dynamic_()) -> {ok, anthropic@streaming:stream_event()} | {error, decode_error()}. decode_content_block_stop(Json) -> Decoder = begin gleam@dynamic@decode:field( <<"index"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Index) -> gleam@dynamic@decode:success(Index) end ) end, case gleam@dynamic@decode:run(Json, Decoder) of {ok, Index@1} -> {ok, {content_block_stop_event, {content_block_stop, Index@1}}}; {error, Errors} -> {error, {json_parse_error, <<"Failed to decode content_block_stop: "/utf8, (format_errors(Errors))/binary>>}} end. -file("src/anthropic/streaming/decoder.gleam", 233). ?DOC(" Decode a message_delta event\n"). -spec decode_message_delta(gleam@dynamic:dynamic_()) -> {ok, anthropic@streaming:stream_event()} | {error, decode_error()}. decode_message_delta(Json) -> Decoder = begin gleam@dynamic@decode:field( <<"delta"/utf8>>, message_delta_inner_decoder(), fun(Delta) -> gleam@dynamic@decode:field( <<"usage"/utf8>>, message_delta_usage_decoder(), fun(Usage) -> gleam@dynamic@decode:success({Delta, Usage}) end ) end ) end, case gleam@dynamic@decode:run(Json, Decoder) of {ok, {Delta@1, Usage@1}} -> {ok, {message_delta_event_variant, {message_delta_event, Delta@1, Usage@1}}}; {error, Errors} -> {error, {json_parse_error, <<"Failed to decode message_delta: "/utf8, (format_errors(Errors))/binary>>}} end. -file("src/anthropic/streaming/decoder.gleam", 281). ?DOC(" Decode an error event\n"). -spec decode_error(gleam@dynamic:dynamic_()) -> {ok, anthropic@streaming:stream_event()} | {error, decode_error()}. decode_error(Json) -> Decoder = begin gleam@dynamic@decode:field( <<"error"/utf8>>, error_inner_decoder(), fun(Error) -> gleam@dynamic@decode:success(Error) end ) end, case gleam@dynamic@decode:run(Json, Decoder) of {ok, Error@1} -> {ok, {error_event, Error@1}}; {error, Errors} -> {error, {json_parse_error, <<"Failed to decode error: "/utf8, (format_errors(Errors))/binary>>}} end. -file("src/anthropic/streaming/decoder.gleam", 71). ?DOC(" Decode a typed event from parsed JSON\n"). -spec decode_typed_event(binary(), gleam@dynamic:dynamic_()) -> {ok, anthropic@streaming:stream_event()} | {error, decode_error()}. decode_typed_event(Event_type, Json) -> case Event_type of <<"message_start"/utf8>> -> decode_message_start(Json); <<"content_block_start"/utf8>> -> decode_content_block_start(Json); <<"content_block_delta"/utf8>> -> decode_content_block_delta(Json); <<"content_block_stop"/utf8>> -> decode_content_block_stop(Json); <<"message_delta"/utf8>> -> decode_message_delta(Json); <<"error"/utf8>> -> decode_error(Json); _ -> {error, {unknown_event_type, Event_type}} end. -file("src/anthropic/streaming/decoder.gleam", 60). ?DOC(" Decode an event that has JSON data\n"). -spec decode_data_event(binary(), binary()) -> {ok, anthropic@streaming:stream_event()} | {error, decode_error()}. decode_data_event(Event_type, Data) -> case gleam_json_ffi:decode(Data) of {error, _} -> {error, {json_parse_error, <<"Failed to parse JSON: "/utf8, Data/binary>>}}; {ok, Json} -> decode_typed_event(Event_type, Json) end. -file("src/anthropic/streaming/decoder.gleam", 49). ?DOC(" Decode an SSE event into a StreamEvent\n"). -spec decode_event(anthropic@internal@sse:sse_event()) -> {ok, anthropic@streaming:stream_event()} | {error, decode_error()}. decode_event(Sse_event) -> Event_type = anthropic@internal@sse:get_event_type(Sse_event), case Event_type of <<"ping"/utf8>> -> {ok, ping_event}; <<"message_stop"/utf8>> -> {ok, message_stop_event}; _ -> decode_data_event( Event_type, anthropic@internal@sse:get_data(Sse_event) ) end.