-module(anthropic@streaming@accumulator). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/anthropic/streaming/accumulator.gleam"). -export([new/0, process_event/2, process_events/1, process_events_with_callback/2, build_response/1, accumulate/1, get_accumulated_text/1, get_accumulated_tool_inputs/1, has_content/1, has_error/1, total_tokens/1]). -export_type([accumulator_state/0, content_block_state/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( " Stream accumulator for building complete messages from streaming events\n" "\n" " This module provides utilities for accumulating streaming events into\n" " a complete message response. It tracks content blocks, handles deltas,\n" " and produces the final message with usage statistics.\n" ). -type accumulator_state() :: {accumulator_state, gleam@option:option(binary()), gleam@option:option(binary()), gleam@option:option(anthropic@types@message:role()), gleam@option:option(binary()), gleam@dict:dict(integer(), content_block_state()), gleam@option:option(anthropic@types@request:stop_reason()), gleam@option:option(binary()), integer(), integer(), boolean(), gleam@option:option(anthropic@types@streaming:stream_error())}. -type content_block_state() :: {text_block_state, binary()} | {tool_use_block_state, binary(), binary(), binary()}. -file("src/anthropic/streaming/accumulator.gleam", 71). ?DOC(" Create a new accumulator state\n"). -spec new() -> accumulator_state(). new() -> {accumulator_state, none, none, none, none, maps:new(), none, none, 0, 0, false, none}. -file("src/anthropic/streaming/accumulator.gleam", 127). ?DOC(" Handle message_start event\n"). -spec handle_message_start( accumulator_state(), anthropic@types@streaming:message_start() ) -> accumulator_state(). handle_message_start(State, Msg) -> {accumulator_state, {some, erlang:element(2, Msg)}, {some, erlang:element(3, Msg)}, {some, erlang:element(4, Msg)}, {some, erlang:element(5, Msg)}, erlang:element(6, State), erlang:element(7, State), erlang:element(8, State), erlang:element(2, erlang:element(6, Msg)), erlang:element(10, State), erlang:element(11, State), erlang:element(12, State)}. -file("src/anthropic/streaming/accumulator.gleam", 142). ?DOC(" Handle content_block_start event\n"). -spec handle_content_block_start( accumulator_state(), anthropic@types@streaming:content_block_start() ) -> accumulator_state(). handle_content_block_start(State, Start) -> Block_state = case erlang:element(3, Start) of {text_block, Text} -> {text_block_state, Text}; {tool_use_block, Id, Name, Input} -> {tool_use_block_state, Id, Name, Input}; _ -> {text_block_state, <<""/utf8>>} end, {accumulator_state, erlang:element(2, State), erlang:element(3, State), erlang:element(4, State), erlang:element(5, State), gleam@dict:insert( erlang:element(6, State), erlang:element(2, Start), Block_state ), erlang:element(7, State), erlang:element(8, State), erlang:element(9, State), erlang:element(10, State), erlang:element(11, State), erlang:element(12, State)}. -file("src/anthropic/streaming/accumulator.gleam", 184). ?DOC(" Apply a delta to a content block state\n"). -spec apply_delta( content_block_state(), anthropic@types@streaming:content_block_delta() ) -> content_block_state(). apply_delta(Block_state, Delta) -> case {Block_state, Delta} of {{text_block_state, Text}, {text_content_delta, Text_delta}} -> {text_block_state, <>}; {{tool_use_block_state, Id, Name, Input}, {input_json_content_delta, Json_delta}} -> {tool_use_block_state, Id, Name, <>}; {_, _} -> Block_state end. -file("src/anthropic/streaming/accumulator.gleam", 160). ?DOC(" Handle content_block_delta event\n"). -spec handle_content_block_delta( accumulator_state(), anthropic@types@streaming:content_block_delta_event() ) -> accumulator_state(). handle_content_block_delta(State, Delta) -> Updated_blocks = case gleam_stdlib:map_get( erlang:element(6, State), erlang:element(2, Delta) ) of {ok, Block_state} -> New_block_state = apply_delta(Block_state, erlang:element(3, Delta)), gleam@dict:insert( erlang:element(6, State), erlang:element(2, Delta), New_block_state ); {error, _} -> New_block_state@1 = case erlang:element(3, Delta) of {text_content_delta, Text_delta} -> {text_block_state, erlang:element(2, Text_delta)}; {input_json_content_delta, Json_delta} -> {tool_use_block_state, <<""/utf8>>, <<""/utf8>>, erlang:element(2, Json_delta)} end, gleam@dict:insert( erlang:element(6, State), erlang:element(2, Delta), New_block_state@1 ) end, {accumulator_state, erlang:element(2, State), erlang:element(3, State), erlang:element(4, State), erlang:element(5, State), Updated_blocks, erlang:element(7, State), erlang:element(8, State), erlang:element(9, State), erlang:element(10, State), erlang:element(11, State), erlang:element(12, State)}. -file("src/anthropic/streaming/accumulator.gleam", 202). ?DOC(" Handle message_delta event\n"). -spec handle_message_delta( accumulator_state(), anthropic@types@streaming:message_delta_event() ) -> accumulator_state(). handle_message_delta(State, Delta) -> {accumulator_state, erlang:element(2, State), erlang:element(3, State), erlang:element(4, State), erlang:element(5, State), erlang:element(6, State), erlang:element(2, erlang:element(2, Delta)), erlang:element(3, erlang:element(2, Delta)), erlang:element(9, State), erlang:element(2, erlang:element(3, Delta)), erlang:element(11, State), erlang:element(12, State)}. -file("src/anthropic/streaming/accumulator.gleam", 88). ?DOC(" Process a single event and update accumulator state\n"). -spec process_event( accumulator_state(), anthropic@types@streaming:stream_event() ) -> accumulator_state(). process_event(State, Event) -> case Event of {message_start_event, Msg} -> handle_message_start(State, Msg); {content_block_start_event, Start} -> handle_content_block_start(State, Start); {content_block_delta_event_variant, Delta} -> handle_content_block_delta(State, Delta); {content_block_stop_event, _} -> State; {message_delta_event_variant, Delta@1} -> handle_message_delta(State, Delta@1); message_stop_event -> {accumulator_state, erlang:element(2, State), erlang:element(3, State), erlang:element(4, State), erlang:element(5, State), erlang:element(6, State), erlang:element(7, State), erlang:element(8, State), erlang:element(9, State), erlang:element(10, State), true, erlang:element(12, State)}; ping_event -> State; {error_event, Err} -> {accumulator_state, erlang:element(2, State), erlang:element(3, State), erlang:element(4, State), erlang:element(5, State), erlang:element(6, State), erlang:element(7, State), erlang:element(8, State), erlang:element(9, State), erlang:element(10, State), erlang:element(11, State), {some, Err}} end. -file("src/anthropic/streaming/accumulator.gleam", 106). ?DOC(" Process multiple events and return final state\n"). -spec process_events(list(anthropic@types@streaming:stream_event())) -> accumulator_state(). process_events(Events) -> gleam@list:fold(Events, new(), fun process_event/2). -file("src/anthropic/streaming/accumulator.gleam", 111). ?DOC(" Process events with a callback for each event\n"). -spec process_events_with_callback( list(anthropic@types@streaming:stream_event()), fun((anthropic@types@streaming:stream_event(), accumulator_state()) -> nil) ) -> accumulator_state(). process_events_with_callback(Events, Callback) -> gleam@list:fold( Events, new(), fun(State, Event) -> New_state = process_event(State, Event), Callback(Event, New_state), New_state end ). -file("src/anthropic/streaming/accumulator.gleam", 244). ?DOC(" Build content blocks from accumulated state\n"). -spec build_content_blocks(gleam@dict:dict(integer(), content_block_state())) -> list(anthropic@types@message:content_block()). build_content_blocks(Blocks) -> _pipe = Blocks, _pipe@1 = maps:to_list(_pipe), _pipe@2 = gleam@list:sort( _pipe@1, fun(A, B) -> {Index_a, _} = A, {Index_b, _} = B, case Index_a < Index_b of true -> lt; false -> case Index_a > Index_b of true -> gt; false -> eq end end end ), gleam@list:map( _pipe@2, fun(Pair) -> {_, Block_state} = Pair, case Block_state of {text_block_state, Text} -> {text_block, Text}; {tool_use_block_state, Id, Name, Input} -> {tool_use_block, Id, Name, Input} end end ). -file("src/anthropic/streaming/accumulator.gleam", 272). ?DOC(" Helper for requiring Option values with use syntax\n"). -spec require_some( gleam@option:option(GTZ), binary(), fun((GTZ) -> {ok, GUB} | {error, binary()}) ) -> {ok, GUB} | {error, binary()}. require_some(Opt, Error_msg, Next) -> case Opt of {some, Value} -> Next(Value); none -> {error, Error_msg} end. -file("src/anthropic/streaming/accumulator.gleam", 219). ?DOC(" Build a CreateMessageResponse from the accumulated state\n"). -spec build_response(accumulator_state()) -> {ok, anthropic@types@request:create_message_response()} | {error, binary()}. build_response(State) -> require_some( erlang:element(2, State), <<"Missing message ID"/utf8>>, fun(Id) -> require_some( erlang:element(4, State), <<"Missing role"/utf8>>, fun(Role) -> require_some( erlang:element(5, State), <<"Missing model"/utf8>>, fun(Model) -> Content = build_content_blocks( erlang:element(6, State) ), {ok, {create_message_response, Id, gleam@option:unwrap( erlang:element(3, State), <<"message"/utf8>> ), Role, Content, Model, erlang:element(7, State), erlang:element(8, State), {usage, erlang:element(9, State), erlang:element(10, State)}}} end ) end ) end ). -file("src/anthropic/streaming/accumulator.gleam", 288). ?DOC(" Accumulate events and build final response\n"). -spec accumulate(list(anthropic@types@streaming:stream_event())) -> {ok, anthropic@types@request:create_message_response()} | {error, binary()}. accumulate(Events) -> State = process_events(Events), build_response(State). -file("src/anthropic/streaming/accumulator.gleam", 296). ?DOC(" Get the accumulated text so far\n"). -spec get_accumulated_text(accumulator_state()) -> binary(). get_accumulated_text(State) -> _pipe = erlang:element(6, State), _pipe@1 = maps:values(_pipe), _pipe@2 = gleam@list:filter_map(_pipe@1, fun(Block) -> case Block of {text_block_state, Text} -> {ok, Text}; _ -> {error, nil} end end), gleam@string:join(_pipe@2, <<""/utf8>>). -file("src/anthropic/streaming/accumulator.gleam", 309). ?DOC(" Get the accumulated tool inputs so far\n"). -spec get_accumulated_tool_inputs(accumulator_state()) -> list({binary(), binary(), binary()}). get_accumulated_tool_inputs(State) -> _pipe = erlang:element(6, State), _pipe@1 = maps:values(_pipe), gleam@list:filter_map(_pipe@1, fun(Block) -> case Block of {tool_use_block_state, Id, Name, Input} -> {ok, {Id, Name, Input}}; _ -> {error, nil} end end). -file("src/anthropic/streaming/accumulator.gleam", 323). ?DOC(" Check if accumulator has any content\n"). -spec has_content(accumulator_state()) -> boolean(). has_content(State) -> maps:size(erlang:element(6, State)) > 0. -file("src/anthropic/streaming/accumulator.gleam", 328). ?DOC(" Check if accumulator encountered an error\n"). -spec has_error(accumulator_state()) -> boolean(). has_error(State) -> gleam@option:is_some(erlang:element(12, State)). -file("src/anthropic/streaming/accumulator.gleam", 333). ?DOC(" Get total token count\n"). -spec total_tokens(accumulator_state()) -> integer(). total_tokens(State) -> erlang:element(9, State) + erlang:element(10, State).