-module(glean@run). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/glean/run.gleam"). -export([stream/4, generate/3, generate_messages/3, continue/4]). -export_type([run_result/0, step_result/0, run_state/1, pending_tool_call/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. -type run_result() :: {run_result, binary(), list(glean@message:message()), list(glean@provider:generated_content()), glean@stream:usage(), glean@error:finish_reason(), integer(), list(step_result())}. -type step_result() :: {step_result, integer(), list(glean@provider:generated_content()), glean@error:finish_reason(), glean@stream:usage()}. -type run_state(LGE) :: {run_state, glean@agent:agent(LGE), LGE, list(glean@message:message()), integer(), glean@stream:usage(), list(step_result())}. -type pending_tool_call() :: {pending_tool_call, binary(), binary(), binary()}. -file("src/glean/run.gleam", 134). -spec build_initial_messages(glean@agent:agent(any()), binary()) -> list(glean@message:message()). build_initial_messages(Agent, Prompt) -> System_msgs = begin _pipe = erlang:element(3, Agent), gleam@list:map(_pipe, fun glean@message:system/1) end, lists:append(System_msgs, [glean@message:user(Prompt)]). -file("src/glean/run.gleam", 142). -spec prepend_system_prompts( glean@agent:agent(any()), list(glean@message:message()) ) -> list(glean@message:message()). prepend_system_prompts(Agent, Messages) -> System_msgs = begin _pipe = erlang:element(3, Agent), gleam@list:map(_pipe, fun glean@message:system/1) end, lists:append(System_msgs, Messages). -file("src/glean/run.gleam", 385). -spec extract_tool_calls(list(glean@provider:generated_content())) -> list(pending_tool_call()). extract_tool_calls(Content) -> gleam@list:filter_map(Content, fun(C) -> case C of {generated_tool_call, Id, Name, Args} -> {ok, {pending_tool_call, Id, Name, Args}}; _ -> {error, nil} end end). -file("src/glean/run.gleam", 399). -spec extract_text(list(glean@provider:generated_content())) -> binary(). extract_text(Content) -> _pipe = Content, _pipe@1 = gleam@list:filter_map(_pipe, fun(C) -> case C of {generated_text, Text} -> {ok, Text}; _ -> {error, nil} end end), gleam@list:fold( _pipe@1, <<""/utf8>>, fun(Acc, Text@1) -> <> end ). -file("src/glean/run.gleam", 548). -spec tool_error_to_string(glean@error:glean_error()) -> binary(). tool_error_to_string(Err) -> case Err of {tool_execution_error, _, _, Reason} -> Reason; {tool_input_validation_error, _, _, Errors} -> _pipe = Errors, _pipe@1 = gleam@list:map(_pipe, fun(E) -> erlang:element(3, E) end), gleam@list:fold( _pipe@1, <<"Validation errors: "/utf8>>, fun(Acc, Msg) -> <<<>/binary, "; "/utf8>> end ); _ -> <<"Tool execution failed"/utf8>> end. -file("src/glean/run.gleam", 492). -spec execute_tool_with_retry( run_state(LJA), pending_tool_call(), glean@tool:tool(LJA), integer() ) -> {ok, glean@message:tool_result()} | {error, glean@error:glean_error()}. execute_tool_with_retry(State, Call, Found_tool, Attempt) -> Ctx = {tool_context, erlang:element(3, State), erlang:element(2, Call), erlang:element(3, Call), Attempt, erlang:element(6, Found_tool), erlang:element(5, State)}, case (erlang:element(5, Found_tool))(Ctx, erlang:element(4, Call)) of {ok, Output} -> {ok, {tool_result_ok, erlang:element(2, Call), erlang:element(3, Call), Output}}; {error, Tool_err} -> case Attempt < erlang:element(6, Found_tool) of true -> case Tool_err of {tool_not_found, _} -> {ok, {tool_result_error, erlang:element(2, Call), erlang:element(3, Call), tool_error_to_string(Tool_err)}}; _ -> execute_tool_with_retry( State, Call, Found_tool, Attempt + 1 ) end; false -> {ok, {tool_result_error, erlang:element(2, Call), erlang:element(3, Call), tool_error_to_string(Tool_err)}} end end. -file("src/glean/run.gleam", 481). -spec execute_single_tool(run_state(any()), pending_tool_call()) -> {ok, glean@message:tool_result()} | {error, glean@error:glean_error()}. execute_single_tool(State, Call) -> case glean@tool:find( erlang:element(4, erlang:element(2, State)), erlang:element(3, Call) ) of {error, Err} -> {error, Err}; {ok, Found_tool} -> execute_tool_with_retry(State, Call, Found_tool, 0) end. -file("src/glean/run.gleam", 417). -spec execute_tool_calls_loop( run_state(any()), list(pending_tool_call()), list(glean@message:tool_result()) ) -> {ok, list(glean@message:tool_result())} | {error, glean@error:glean_error()}. execute_tool_calls_loop(State, Calls, Results) -> case Calls of [] -> {ok, lists:reverse(Results)}; [Call | Rest] -> case execute_single_tool(State, Call) of {error, Err} -> {error, Err}; {ok, Result} -> execute_tool_calls_loop(State, Rest, [Result | Results]) end end. -file("src/glean/run.gleam", 410). -spec execute_tool_calls(run_state(any()), list(pending_tool_call())) -> {ok, list(glean@message:tool_result())} | {error, glean@error:glean_error()}. execute_tool_calls(State, Calls) -> execute_tool_calls_loop(State, Calls, []). -file("src/glean/run.gleam", 183). -spec process_generate_result( run_state(any()), glean@provider:generate_result() ) -> {ok, run_result()} | {error, glean@error:glean_error()}. process_generate_result(State, Result) -> Step_result = {step_result, erlang:element(5, State), erlang:element(2, Result), erlang:element(3, Result), erlang:element(4, Result)}, New_usage = glean@stream:add_usage( erlang:element(6, State), erlang:element(4, Result) ), New_step_results = lists:append(erlang:element(7, State), [Step_result]), Tool_calls = extract_tool_calls(erlang:element(2, Result)), case Tool_calls of [] -> Text = extract_text(erlang:element(2, Result)), {ok, {run_result, Text, erlang:element(4, State), erlang:element(2, Result), New_usage, erlang:element(3, Result), erlang:element(5, State) + 1, New_step_results}}; _ -> Assistant_content = begin _pipe = erlang:element(2, Result), gleam@list:map(_pipe, fun(C) -> case C of {generated_tool_call, Id, Name, Args} -> {assistant_tool_call, Id, Name, Args}; {generated_text, Text@1} -> {assistant_text, Text@1}; {generated_reasoning, Text@2} -> {assistant_reasoning, Text@2} end end) end, Messages_with_assistant = lists:append( erlang:element(4, State), [{assistant_message, Assistant_content}] ), case execute_tool_calls(State, Tool_calls) of {error, Err} -> {error, Err}; {ok, Tool_results} -> Messages_with_results = lists:append( Messages_with_assistant, [{tool_result_message, Tool_results}] ), run_loop( {run_state, erlang:element(2, State), erlang:element(3, State), Messages_with_results, erlang:element(5, State) + 1, New_usage, New_step_results} ) end end. -file("src/glean/run.gleam", 155). -spec run_loop(run_state(any())) -> {ok, run_result()} | {error, glean@error:glean_error()}. run_loop(State) -> case erlang:element(5, State) >= erlang:element(7, erlang:element(2, State)) of true -> {error, {max_steps_exceeded, erlang:element(7, erlang:element(2, State)), erlang:element(5, State)}}; false -> Request = {generate_request, erlang:element(4, State), erlang:element(5, erlang:element(2, State)), glean@tool:to_specs(erlang:element(4, erlang:element(2, State))), erlang:element(6, erlang:element(2, State)), text_format}, case (erlang:element(4, erlang:element(2, erlang:element(2, State))))( Request ) of {error, Err} -> {error, Err}; {ok, Result} -> process_generate_result(State, Result) end end. -file("src/glean/run.gleam", 263). -spec run_stream_loop( run_state(any()), fun((glean@stream:stream_event()) -> nil) ) -> {ok, run_result()} | {error, glean@error:glean_error()}. run_stream_loop(State, On_event) -> case erlang:element(5, State) >= erlang:element(7, erlang:element(2, State)) of true -> {error, {max_steps_exceeded, erlang:element(7, erlang:element(2, State)), erlang:element(5, State)}}; false -> On_event({step_start, erlang:element(5, State)}), Request = {generate_request, erlang:element(4, State), erlang:element(5, erlang:element(2, State)), glean@tool:to_specs(erlang:element(4, erlang:element(2, State))), erlang:element(6, erlang:element(2, State)), text_format}, case (erlang:element(5, erlang:element(2, erlang:element(2, State))))( Request, On_event ) of {error, Err} -> {error, Err}; {ok, Result} -> On_event({step_end, erlang:element(5, State)}), process_stream_result(State, Result, On_event) end end. -file("src/glean/run.gleam", 296). -spec process_stream_result( run_state(any()), glean@provider:generate_result(), fun((glean@stream:stream_event()) -> nil) ) -> {ok, run_result()} | {error, glean@error:glean_error()}. process_stream_result(State, Result, On_event) -> Step_result = {step_result, erlang:element(5, State), erlang:element(2, Result), erlang:element(3, Result), erlang:element(4, Result)}, New_usage = glean@stream:add_usage( erlang:element(6, State), erlang:element(4, Result) ), New_step_results = lists:append(erlang:element(7, State), [Step_result]), Tool_calls = extract_tool_calls(erlang:element(2, Result)), case Tool_calls of [] -> Text = extract_text(erlang:element(2, Result)), On_event({finish, erlang:element(3, Result), New_usage}), {ok, {run_result, Text, erlang:element(4, State), erlang:element(2, Result), New_usage, erlang:element(3, Result), erlang:element(5, State) + 1, New_step_results}}; _ -> Assistant_content = begin _pipe = erlang:element(2, Result), gleam@list:map(_pipe, fun(C) -> case C of {generated_tool_call, Id, Name, Args} -> {assistant_tool_call, Id, Name, Args}; {generated_text, Text@1} -> {assistant_text, Text@1}; {generated_reasoning, Text@2} -> {assistant_reasoning, Text@2} end end) end, Messages_with_assistant = lists:append( erlang:element(4, State), [{assistant_message, Assistant_content}] ), case execute_tool_calls_with_events(State, Tool_calls, On_event) of {error, Err} -> {error, Err}; {ok, Tool_results} -> Messages_with_results = lists:append( Messages_with_assistant, [{tool_result_message, Tool_results}] ), run_stream_loop( {run_state, erlang:element(2, State), erlang:element(3, State), Messages_with_results, erlang:element(5, State) + 1, New_usage, New_step_results}, On_event ) end end. -file("src/glean/run.gleam", 434). -spec execute_tool_calls_with_events( run_state(any()), list(pending_tool_call()), fun((glean@stream:stream_event()) -> nil) ) -> {ok, list(glean@message:tool_result())} | {error, glean@error:glean_error()}. execute_tool_calls_with_events(State, Calls, On_event) -> execute_tool_calls_with_events_loop(State, Calls, [], On_event). -file("src/glean/run.gleam", 442). -spec execute_tool_calls_with_events_loop( run_state(any()), list(pending_tool_call()), list(glean@message:tool_result()), fun((glean@stream:stream_event()) -> nil) ) -> {ok, list(glean@message:tool_result())} | {error, glean@error:glean_error()}. execute_tool_calls_with_events_loop(State, Calls, Results, On_event) -> case Calls of [] -> {ok, lists:reverse(Results)}; [Call | Rest] -> case execute_single_tool(State, Call) of {error, Err} -> {error, Err}; {ok, Result} -> case Result of {tool_result_ok, Tool_call_id, Tool_name, Output} -> On_event( {tool_result_event, Tool_call_id, Tool_name, Output} ); {tool_result_error, Tool_call_id@1, Tool_name@1, Error_message} -> On_event( {tool_error_event, Tool_call_id@1, Tool_name@1, Error_message} ) end, execute_tool_calls_with_events_loop( State, Rest, [Result | Results], On_event ) end end. -file("src/glean/run.gleam", 94). ?DOC(" Run the agent with streaming. Calls on_event for each StreamEvent.\n"). -spec stream( glean@agent:agent(LGO), LGO, binary(), fun((glean@stream:stream_event()) -> nil) ) -> {ok, run_result()} | {error, glean@error:glean_error()}. stream(Agent, Deps, Prompt, On_event) -> Messages = build_initial_messages(Agent, Prompt), run_stream_loop( {run_state, Agent, Deps, Messages, 0, glean@stream:zero_usage(), []}, On_event ). -file("src/glean/run.gleam", 60). ?DOC(" Run the agent with a simple text prompt.\n"). -spec generate(glean@agent:agent(LGF), LGF, binary()) -> {ok, run_result()} | {error, glean@error:glean_error()}. generate(Agent, Deps, Prompt) -> Messages = build_initial_messages(Agent, Prompt), run_loop( {run_state, Agent, Deps, Messages, 0, glean@stream:zero_usage(), []} ). -file("src/glean/run.gleam", 77). ?DOC(" Run the agent with pre-built messages (for multi-turn conversations).\n"). -spec generate_messages( glean@agent:agent(LGJ), LGJ, list(glean@message:message()) ) -> {ok, run_result()} | {error, glean@error:glean_error()}. generate_messages(Agent, Deps, Messages) -> Messages@1 = prepend_system_prompts(Agent, Messages), run_loop( {run_state, Agent, Deps, Messages@1, 0, glean@stream:zero_usage(), []} ). -file("src/glean/run.gleam", 115). ?DOC(" Continue a previous run with additional user input.\n"). -spec continue(glean@agent:agent(LGS), LGS, run_result(), binary()) -> {ok, run_result()} | {error, glean@error:glean_error()}. continue(Agent, Deps, Previous, Prompt) -> Messages = lists:append( erlang:element(3, Previous), [glean@message:user(Prompt)] ), run_loop( {run_state, Agent, Deps, Messages, 0, glean@stream:zero_usage(), []} ).