Packages

A Gleam library for building and orchestrating agents on the BEAM.

Current section

Files

Jump to
pig src pig@obs@terminal.erl
Raw

src/pig@obs@terminal.erl

-module(pig@obs@terminal).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/pig/obs/terminal.gleam").
-export([format_event/1, start/0, start_consumer/0, supervised/1]).
-export_type([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(
" Terminal pretty printer for SessionEvents.\n"
"\n"
" OTP actor that receives SessionEvents and prints formatted output.\n"
" Pure `format_event` function for testing without side effects.\n"
).
-type state() :: state.
-file("src/pig/obs/terminal.gleam", 129).
?DOC(" Format a SessionEndReason for display.\n").
-spec format_end_reason(pig@obs@events:session_end_reason()) -> binary().
format_end_reason(Reason) ->
case Reason of
normal_end ->
<<"normal"/utf8>>;
{error_end, _} ->
<<"error"/utf8>>;
{max_iterations_exceeded, N} ->
<<<<"max_iterations_exceeded ("/utf8,
(erlang:integer_to_binary(N))/binary>>/binary,
" iterations)"/utf8>>;
interrupted ->
<<"interrupted"/utf8>>
end.
-file("src/pig/obs/terminal.gleam", 119).
?DOC(" Format an AiError for display.\n").
-spec format_error(pig_protocol@error:ai_error()) -> binary().
format_error(Error) ->
case Error of
{api_error, Msg} ->
<<"ApiError: "/utf8, Msg/binary>>;
rate_limited ->
<<"RateLimited"/utf8>>;
timeout ->
<<"Timeout"/utf8>>;
{invalid_response, Detail} ->
<<"InvalidResponse: "/utf8, Detail/binary>>
end.
-file("src/pig/obs/terminal.gleam", 141).
?DOC(" Format a HookPoint for display.\n").
-spec hook_to_string(pig@obs@events:hook_point()) -> binary().
hook_to_string(Hook) ->
case Hook of
on_session_start ->
<<"on_session_start"/utf8>>;
on_session_shutdown ->
<<"on_session_shutdown"/utf8>>;
before_inference ->
<<"before_inference"/utf8>>;
after_inference ->
<<"after_inference"/utf8>>;
before_tool_call ->
<<"before_tool_call"/utf8>>;
after_tool_call ->
<<"after_tool_call"/utf8>>;
on_error ->
<<"on_error"/utf8>>;
on_complete ->
<<"on_complete"/utf8>>
end.
-file("src/pig/obs/terminal.gleam", 32).
?DOC(
" Format a SessionEvent as a human-readable string.\n"
" This function is pure and has no side effects, making it easy to test.\n"
).
-spec format_event(pig@obs@events:session_event()) -> binary().
format_event(Event) ->
case Event of
{session_started, _, Agent_name, Model, _, _} ->
Agent_part = case Agent_name of
{some, Name} ->
<<" | agent: "/utf8, Name/binary>>;
none ->
<<""/utf8>>
end,
<<<<"[START] Session started | model: "/utf8, Model/binary>>/binary,
Agent_part/binary>>;
{inference_started, Model@1, Message_count} ->
<<<<<<"[INF] Started | model: "/utf8, Model@1/binary>>/binary,
" | messages: "/utf8>>/binary,
(erlang:integer_to_binary(Message_count))/binary>>;
{inference_completed,
_,
_,
_,
Stop_reason,
Input_tokens,
Output_tokens,
Duration_ms,
_} ->
Duration_str = <<(erlang:integer_to_binary(Duration_ms))/binary,
"ms"/utf8>>,
Token_part = case {Input_tokens, Output_tokens} of
{{some, Input}, {some, Output}} ->
<<<<<<" | tokens: "/utf8,
(erlang:integer_to_binary(Input))/binary>>/binary,
"→"/utf8>>/binary,
(erlang:integer_to_binary(Output))/binary>>;
{_, _} ->
<<""/utf8>>
end,
Finish_part = case Stop_reason of
{some, Reason} ->
<<" | finish: "/utf8,
(pig_protocol@stop_reason:to_string(Reason))/binary>>;
none ->
<<""/utf8>>
end,
<<<<<<"[INF] Completed | "/utf8, Duration_str/binary>>/binary,
Token_part/binary>>/binary,
Finish_part/binary>>;
{tool_started, Tool_call} ->
<<"[TOOL] Started | "/utf8, (erlang:element(3, Tool_call))/binary>>;
{tool_executed, Tool_call@1, _, Duration_ms@1} ->
Duration_str@1 = <<(erlang:integer_to_binary(Duration_ms@1))/binary,
"ms"/utf8>>,
<<<<<<"[TOOL] "/utf8, (erlang:element(3, Tool_call@1))/binary>>/binary,
" | "/utf8>>/binary,
Duration_str@1/binary>>;
{tool_blocked, Tool_call@2, Hook_name, Reason@1} ->
<<<<<<<<<<"[TOOL] Blocked | "/utf8,
(erlang:element(3, Tool_call@2))/binary>>/binary,
" | "/utf8>>/binary,
Hook_name/binary>>/binary,
" | "/utf8>>/binary,
Reason@1/binary>>;
{hook_acted, Hook_name@1, Hook_point, Action} ->
<<<<<<<<<<"[HOOK] "/utf8, Hook_name@1/binary>>/binary, " | "/utf8>>/binary,
(hook_to_string(Hook_point))/binary>>/binary,
" | "/utf8>>/binary,
(erlang:element(2, Action))/binary>>;
{inference_failed, Error, Duration_ms@2, _} ->
Duration_str@2 = <<(erlang:integer_to_binary(Duration_ms@2))/binary,
"ms"/utf8>>,
Error_str = format_error(Error),
<<<<<<"[ERR] Inference failed | "/utf8, Duration_str@2/binary>>/binary,
" | "/utf8>>/binary,
Error_str/binary>>;
{session_ended, Reason@2} ->
<<"[END] Session ended | "/utf8,
(format_end_reason(Reason@2))/binary>>
end.
-file("src/pig/obs/terminal.gleam", 194).
?DOC(" Handle incoming messages to the printer actor.\n").
-spec handle_message(state(), pig@obs@events:session_event()) -> gleam@otp@actor:next(state(), pig@obs@events:session_event()).
handle_message(State, Event) ->
Formatted = format_event(Event),
gleam_stdlib:println(Formatted),
gleam@otp@actor:continue(State).
-file("src/pig/obs/terminal.gleam", 158).
?DOC(
" Start the terminal printer actor.\n"
" The actor will print formatted SessionEvents to stdout.\n"
).
-spec start() -> {ok,
gleam@erlang@process:subject(pig@obs@events:session_event())} |
{error, gleam@otp@actor:start_error()}.
start() ->
Builder = begin
_pipe = gleam@otp@actor:new(state),
gleam@otp@actor:on_message(_pipe, fun handle_message/2)
end,
case gleam@otp@actor:start(Builder) of
{ok, Started} ->
{ok, erlang:element(3, Started)};
{error, E} ->
{error, E}
end.
-file("src/pig/obs/terminal.gleam", 172).
?DOC(
" Start a terminal consumer actor that accepts SessionEvent directly.\n"
" Used by the dispatcher to fan out events. Returns the Subject for registration.\n"
" This is the consumer version of the actor — same as start() since terminal\n"
" already receives SessionEvent directly.\n"
).
-spec start_consumer() -> {ok,
gleam@erlang@process:subject(pig@obs@events:session_event())} |
{error, gleam@otp@actor:start_error()}.
start_consumer() ->
start().
-file("src/pig/obs/terminal.gleam", 178).
?DOC(
" Create a supervised terminal consumer actor for use in a supervision tree.\n"
" The supervised actor's message type is SessionEvent.\n"
).
-spec supervised(gleam@erlang@process:name(pig@obs@events:session_event())) -> gleam@otp@supervision:child_specification(nil).
supervised(Name) ->
gleam@otp@supervision:worker(
fun() ->
Builder = begin
_pipe = gleam@otp@actor:new(state),
_pipe@1 = gleam@otp@actor:on_message(
_pipe,
fun handle_message/2
),
gleam@otp@actor:named(_pipe@1, Name)
end,
case gleam@otp@actor:start(Builder) of
{ok, Started} ->
{ok, {started, erlang:element(2, Started), nil}};
{error, E} ->
{error, E}
end
end
).