-module(anthropic@hooks). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/anthropic/hooks.gleam"). -export([summarize_request/1, summarize_response/1, default_hooks/0, no_hooks/0, with_on_request_start/2, with_on_request_end/2, with_on_retry/2, with_on_stream_event/2, emit_request_start/2, emit_request_end/2, emit_retry/2, emit_stream_event/2, metrics_hooks/1, generate_request_id/0, simple_logging_hooks/0, combine_hooks/2, has_hooks/1]). -export_type([request_start_event/0, request_end_event/0, retry_event/0, stream_event/0, stream_event_type/0, request_summary/0, response_summary/0, hooks/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( " Logging and telemetry hooks for observability\n" "\n" " This module provides optional hooks for monitoring API interactions,\n" " including request lifecycle events, errors, and streaming events.\n" "\n" " ## Hook Points\n" "\n" " - `on_request_start`: Called before sending a request\n" " - `on_request_end`: Called after receiving a response (success or error)\n" " - `on_retry`: Called before each retry attempt\n" " - `on_stream_event`: Called for each streaming event\n" "\n" " ## Example\n" "\n" " ```gleam\n" " let hooks = default_hooks()\n" " |> with_on_request_start(fn(event) {\n" " io.println(\"Starting request to \" <> event.endpoint)\n" " })\n" " |> with_on_request_end(fn(event) {\n" " io.println(\"Request completed in \" <> int.to_string(event.duration_ms) <> \"ms\")\n" " })\n" "\n" " let client = new_client_with_hooks(config, hooks)\n" " ```\n" ). -type request_start_event() :: {request_start_event, binary(), request_summary(), integer(), binary()}. -type request_end_event() :: {request_end_event, binary(), integer(), boolean(), gleam@option:option(response_summary()), gleam@option:option(anthropic@error:anthropic_error()), binary(), integer()}. -type retry_event() :: {retry_event, binary(), integer(), integer(), integer(), anthropic@error:anthropic_error(), binary()}. -type stream_event() :: {stream_event, stream_event_type(), binary(), integer()}. -type stream_event_type() :: stream_opened | message_start | {content_block_start, integer()} | {content_block_delta, integer(), binary()} | {content_block_stop, integer()} | message_delta | message_stop | stream_closed | {stream_error, binary()}. -type request_summary() :: {request_summary, binary(), integer(), integer(), boolean(), integer(), boolean()}. -type response_summary() :: {response_summary, binary(), binary(), gleam@option:option(binary()), integer(), integer(), integer()}. -type hooks() :: {hooks, gleam@option:option(fun((request_start_event()) -> nil)), gleam@option:option(fun((request_end_event()) -> nil)), gleam@option:option(fun((retry_event()) -> nil)), gleam@option:option(fun((stream_event()) -> nil))}. -file("src/anthropic/hooks.gleam", 188). -spec count_messages(list(any())) -> integer(). count_messages(Messages) -> erlang:length(Messages). -file("src/anthropic/hooks.gleam", 192). -spec count_tools(gleam@option:option(list(any()))) -> integer(). count_tools(Tools) -> case Tools of {some, T} -> erlang:length(T); none -> 0 end. -file("src/anthropic/hooks.gleam", 164). ?DOC(" Create a request summary from a CreateMessageRequest\n"). -spec summarize_request(anthropic@request:create_message_request()) -> request_summary(). summarize_request(Request) -> {request_summary, erlang:element(2, Request), count_messages(erlang:element(3, Request)), erlang:element(4, Request), gleam@option:unwrap(erlang:element(10, Request), false), count_tools(erlang:element(12, Request)), gleam@option:is_some(erlang:element(5, Request))}. -file("src/anthropic/hooks.gleam", 199). -spec count_content_blocks(list(any())) -> integer(). count_content_blocks(Blocks) -> erlang:length(Blocks). -file("src/anthropic/hooks.gleam", 176). ?DOC(" Create a response summary from a CreateMessageResponse\n"). -spec summarize_response(anthropic@request:create_message_response()) -> response_summary(). summarize_response(Response) -> {response_summary, erlang:element(2, Response), erlang:element(6, Response), gleam@option:map( erlang:element(7, Response), fun anthropic@request:stop_reason_to_string/1 ), erlang:element(2, erlang:element(9, Response)), erlang:element(3, erlang:element(9, Response)), count_content_blocks(erlang:element(5, Response))}. -file("src/anthropic/hooks.gleam", 222). ?DOC(" Create default hooks (all disabled)\n"). -spec default_hooks() -> hooks(). default_hooks() -> {hooks, none, none, none, none}. -file("src/anthropic/hooks.gleam", 232). ?DOC(" Create hooks with no callbacks (alias for default_hooks)\n"). -spec no_hooks() -> hooks(). no_hooks() -> default_hooks(). -file("src/anthropic/hooks.gleam", 241). ?DOC(" Set the on_request_start hook\n"). -spec with_on_request_start(hooks(), fun((request_start_event()) -> nil)) -> hooks(). with_on_request_start(Hooks, Callback) -> {hooks, {some, Callback}, erlang:element(3, Hooks), erlang:element(4, Hooks), erlang:element(5, Hooks)}. -file("src/anthropic/hooks.gleam", 249). ?DOC(" Set the on_request_end hook\n"). -spec with_on_request_end(hooks(), fun((request_end_event()) -> nil)) -> hooks(). with_on_request_end(Hooks, Callback) -> {hooks, erlang:element(2, Hooks), {some, Callback}, erlang:element(4, Hooks), erlang:element(5, Hooks)}. -file("src/anthropic/hooks.gleam", 257). ?DOC(" Set the on_retry hook\n"). -spec with_on_retry(hooks(), fun((retry_event()) -> nil)) -> hooks(). with_on_retry(Hooks, Callback) -> {hooks, erlang:element(2, Hooks), erlang:element(3, Hooks), {some, Callback}, erlang:element(5, Hooks)}. -file("src/anthropic/hooks.gleam", 262). ?DOC(" Set the on_stream_event hook\n"). -spec with_on_stream_event(hooks(), fun((stream_event()) -> nil)) -> hooks(). with_on_stream_event(Hooks, Callback) -> {hooks, erlang:element(2, Hooks), erlang:element(3, Hooks), erlang:element(4, Hooks), {some, Callback}}. -file("src/anthropic/hooks.gleam", 274). ?DOC(" Emit a request start event\n"). -spec emit_request_start(hooks(), request_start_event()) -> nil. emit_request_start(Hooks, Event) -> case erlang:element(2, Hooks) of {some, Callback} -> Callback(Event); none -> nil end. -file("src/anthropic/hooks.gleam", 282). ?DOC(" Emit a request end event\n"). -spec emit_request_end(hooks(), request_end_event()) -> nil. emit_request_end(Hooks, Event) -> case erlang:element(3, Hooks) of {some, Callback} -> Callback(Event); none -> nil end. -file("src/anthropic/hooks.gleam", 290). ?DOC(" Emit a retry event\n"). -spec emit_retry(hooks(), retry_event()) -> nil. emit_retry(Hooks, Event) -> case erlang:element(4, Hooks) of {some, Callback} -> Callback(Event); none -> nil end. -file("src/anthropic/hooks.gleam", 298). ?DOC(" Emit a stream event\n"). -spec emit_stream_event(hooks(), stream_event()) -> nil. emit_stream_event(Hooks, Event) -> case erlang:element(5, Hooks) of {some, Callback} -> Callback(Event); none -> nil end. -file("src/anthropic/hooks.gleam", 367). ?DOC(" Create a metrics-focused hook (counts and timings only)\n"). -spec metrics_hooks(fun((binary(), integer()) -> nil)) -> hooks(). metrics_hooks(On_metric) -> _pipe = default_hooks(), with_on_request_end( _pipe, fun(Event) -> On_metric(<<"request_duration_ms"/utf8>>, erlang:element(3, Event)), case erlang:element(4, Event) of true -> On_metric(<<"request_success"/utf8>>, 1); false -> On_metric(<<"request_failure"/utf8>>, 1) end, On_metric(<<"retry_count"/utf8>>, erlang:element(8, Event)), case erlang:element(5, Event) of {some, Resp} -> On_metric(<<"input_tokens"/utf8>>, erlang:element(5, Resp)), On_metric(<<"output_tokens"/utf8>>, erlang:element(6, Resp)); none -> nil end end ). -file("src/anthropic/hooks.gleam", 403). -spec get_timestamp_ms() -> integer(). get_timestamp_ms() -> os:system_time() div 1000. -file("src/anthropic/hooks.gleam", 412). -spec random_int(integer(), integer()) -> integer(). random_int(Min, Max) -> Min + rand:uniform(Max - Min). -file("src/anthropic/hooks.gleam", 392). ?DOC(" Generate a unique request ID\n"). -spec generate_request_id() -> binary(). generate_request_id() -> Timestamp = get_timestamp_ms(), Random = random_int(0, 999999), <<<<<<"req_"/utf8, (erlang:integer_to_binary(Timestamp))/binary>>/binary, "_"/utf8>>/binary, (erlang:integer_to_binary(Random))/binary>>. -file("src/anthropic/hooks.gleam", 417). ?DOC(" Simple logging function\n"). -spec log_message(binary(), binary()) -> nil. log_message(Level, Message) -> io:format(<<"[~s] ~s~n"/utf8>>, [Level, Message]). -file("src/anthropic/hooks.gleam", 310). ?DOC(" Create a simple logging hook that prints to stdout\n"). -spec simple_logging_hooks() -> hooks(). simple_logging_hooks() -> _pipe = default_hooks(), _pipe@1 = with_on_request_start( _pipe, fun(Event) -> log_message( <<"REQUEST_START"/utf8>>, <<<<<<<<<<<<<<"endpoint="/utf8, (erlang:element(2, Event))/binary>>/binary, " model="/utf8>>/binary, (erlang:element(2, erlang:element(3, Event)))/binary>>/binary, " messages="/utf8>>/binary, (erlang:integer_to_binary( erlang:element(3, erlang:element(3, Event)) ))/binary>>/binary, " request_id="/utf8>>/binary, (erlang:element(5, Event))/binary>> ) end ), _pipe@2 = with_on_request_end( _pipe@1, fun(Event@1) -> case erlang:element(4, Event@1) of true -> log_message( <<"REQUEST_END"/utf8>>, <<<<<<<<<<"endpoint="/utf8, (erlang:element(2, Event@1))/binary>>/binary, " duration_ms="/utf8>>/binary, (erlang:integer_to_binary( erlang:element(3, Event@1) ))/binary>>/binary, " success=true request_id="/utf8>>/binary, (erlang:element(7, Event@1))/binary>> ); false -> log_message( <<"REQUEST_END"/utf8>>, <<<<<<<<<<"endpoint="/utf8, (erlang:element(2, Event@1))/binary>>/binary, " duration_ms="/utf8>>/binary, (erlang:integer_to_binary( erlang:element(3, Event@1) ))/binary>>/binary, " success=false request_id="/utf8>>/binary, (erlang:element(7, Event@1))/binary>> ) end end ), with_on_retry( _pipe@2, fun(Event@2) -> log_message( <<"RETRY"/utf8>>, <<<<<<<<<<<<<<<<<<"endpoint="/utf8, (erlang:element(2, Event@2))/binary>>/binary, " attempt="/utf8>>/binary, (erlang:integer_to_binary( erlang:element(3, Event@2) ))/binary>>/binary, "/"/utf8>>/binary, (erlang:integer_to_binary( erlang:element(4, Event@2) ))/binary>>/binary, " delay_ms="/utf8>>/binary, (erlang:integer_to_binary( erlang:element(5, Event@2) ))/binary>>/binary, " request_id="/utf8>>/binary, (erlang:element(7, Event@2))/binary>> ) end ). -file("src/anthropic/hooks.gleam", 447). -spec combine_callbacks( gleam@option:option(fun((HVL) -> nil)), gleam@option:option(fun((HVL) -> nil)) ) -> gleam@option:option(fun((HVL) -> nil)). combine_callbacks(First, Second) -> case {First, Second} of {none, none} -> none; {{some, F}, none} -> {some, F}; {none, {some, S}} -> {some, S}; {{some, F@1}, {some, S@1}} -> {some, fun(Event) -> F@1(Event), S@1(Event) end} end. -file("src/anthropic/hooks.gleam", 429). ?DOC(" Combine two hooks, running both callbacks when events occur\n"). -spec combine_hooks(hooks(), hooks()) -> hooks(). combine_hooks(First, Second) -> {hooks, combine_callbacks(erlang:element(2, First), erlang:element(2, Second)), combine_callbacks(erlang:element(3, First), erlang:element(3, Second)), combine_callbacks(erlang:element(4, First), erlang:element(4, Second)), combine_callbacks(erlang:element(5, First), erlang:element(5, Second))}. -file("src/anthropic/hooks.gleam", 464). ?DOC(" Check if any hooks are configured\n"). -spec has_hooks(hooks()) -> boolean(). has_hooks(Hooks) -> ((gleam@option:is_some(erlang:element(2, Hooks)) orelse gleam@option:is_some( erlang:element(3, Hooks) )) orelse gleam@option:is_some(erlang:element(4, Hooks))) orelse gleam@option:is_some(erlang:element(5, Hooks)).