Packages

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

Current section

Files

Jump to
pig src pig@agent@update.erl
Raw

src/pig@agent@update.erl

-module(pig@agent@update).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/pig/agent/update.gleam").
-export([update/2]).
-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(
" Pure agent state machine — the sans-IO update function.\n"
"\n"
" `update(state, msg) -> StepResult(msg)` is a pure function:\n"
" no provider calls, no tool execution, no telemetry, no hooks.\n"
"\n"
" The runtime calls this function, interprets the returned effects,\n"
" and feeds results back as new messages.\n"
).
-file("src/pig/agent/update.gleam", 89).
-spec handle_tool_results(
pig@agent@state:agent_state(),
list({pig_protocol@message:tool_call(),
{ok, gleam@json:json()} | {error, pig@tool:tool_error()}})
) -> pig@agent@step_result:step_result(pig@agent@msg:agent_msg()).
handle_tool_results(St, Results) ->
Tool_messages = gleam@list:map(
Results,
fun(Pair) ->
{Call, Result} = Pair,
Content = case Result of
{ok, Json_val} ->
gleam@json:to_string(Json_val);
{error, Tool_err} ->
<<"Tool error: "/utf8,
(erlang:element(2, Tool_err))/binary>>
end,
{tool, erlang:element(2, Call), Content}
end
),
New_st = begin
_pipe = Tool_messages,
_pipe@1 = gleam@list:fold(_pipe, St, fun pig@agent@state:add_message/2),
pig@agent@state:increment_iterations(_pipe@1)
end,
case pig@agent@state:exceeded_max_iterations(New_st) of
true ->
{failed, New_st, pig@agent@state:max_iterations_error(New_st)};
false ->
Msgs = pig@agent@state:messages_for_provider(New_st),
Tools = pig@agent@state:tool_definitions(New_st),
{continue, New_st, [{call_provider, Msgs, Tools, fun(R) -> case R of
{ok, Ir} ->
{provider_responded,
{ok, erlang:element(2, Ir)}};
{error, E} ->
{provider_responded, {error, E}}
end end}]}
end.
-file("src/pig/agent/update.gleam", 49).
-spec handle_provider_responded(
pig@agent@state:agent_state(),
{ok, pig_protocol@message:message()} |
{error, pig_protocol@error:ai_error()}
) -> pig@agent@step_result:step_result(pig@agent@msg:agent_msg()).
handle_provider_responded(St, Result) ->
case Result of
{ok, {assistant, _, Calls, _, _} = Assistant_msg} ->
case Calls of
[] ->
New_st = pig@agent@state:add_message(St, Assistant_msg),
{done, New_st, Assistant_msg};
_ ->
New_st@1 = pig@agent@state:add_message(St, Assistant_msg),
{continue,
New_st@1,
[{execute_tools,
Calls,
fun(Results) -> {tool_results, Results} end}]}
end;
{ok, Other} ->
New_st@2 = pig@agent@state:add_message(St, Other),
{done, New_st@2, Other};
{error, E} ->
{failed, St, E}
end.
-file("src/pig/agent/update.gleam", 33).
-spec handle_user_prompt(pig@agent@state:agent_state(), binary()) -> pig@agent@step_result:step_result(pig@agent@msg:agent_msg()).
handle_user_prompt(St, Prompt) ->
New_st = pig@agent@state:add_message(St, {user, Prompt}),
Msgs = pig@agent@state:messages_for_provider(New_st),
Tools = pig@agent@state:tool_definitions(New_st),
{continue, New_st, [{call_provider, Msgs, Tools, fun(R) -> case R of
{ok, Ir} ->
{provider_responded, {ok, erlang:element(2, Ir)}};
{error, E} ->
{provider_responded, {error, E}}
end end}]}.
-file("src/pig/agent/update.gleam", 23).
?DOC(
" Pure state transition: given current state and a message, return\n"
" the next state and any effects the runtime should execute.\n"
"\n"
" This is the entire agent loop logic, sans IO.\n"
).
-spec update(pig@agent@state:agent_state(), pig@agent@msg:agent_msg()) -> pig@agent@step_result:step_result(pig@agent@msg:agent_msg()).
update(St, M) ->
case M of
{user_prompt, Prompt} ->
handle_user_prompt(St, Prompt);
{provider_responded, Result} ->
handle_provider_responded(St, Result);
{tool_results, Results} ->
handle_tool_results(St, Results)
end.