defmodule Magus.GraphAgent do alias Magus.GraphAgent defstruct [ :name, :entry_point_node, initial_state: %{}, graph: Graph.new(), final_output_property: nil, node_to_fn: %{}, node_to_conditional_fn: %{}, cleanup_fn: nil ] @type t() :: %GraphAgent{} @type node_name() :: atom() @spec add_node(t(), node_name(), fun()) :: t() def add_node(agent, node, node_fn) do g = agent.graph |> Graph.add_vertex(node) node_to_fn = agent.node_to_fn |> Map.put(node, node_fn) %{agent | graph: g, node_to_fn: node_to_fn} end @spec add_edge(t(), node_name(), node_name()) :: t() def add_edge(agent, node_a, node_b) do g = agent.graph |> Graph.add_edge(node_a, node_b) %{agent | graph: g} end @spec add_conditional_edges(t(), node_name(), list(node_name()), fun()) :: t() def add_conditional_edges(agent, node_a, possible_nodes, conditional_fn) do edges = Enum.map(possible_nodes, fn end_node -> {node_a, end_node} end) g = agent.graph |> Graph.add_edges(edges) %{ agent | graph: g, node_to_conditional_fn: Map.put(agent.node_to_conditional_fn, node_a, conditional_fn) } end @spec set_entry_point(t(), node_name()) :: t() def set_entry_point(agent, node) do %{agent | entry_point_node: node} end @spec get_final_output(t(), any()) :: any() def get_final_output(%GraphAgent{final_output_property: nil}, _cur_state) do # No final output property specified "" end @spec get_final_output(t(), any()) :: any() def get_final_output(agent, cur_state) do Map.fetch!(cur_state, agent.final_output_property) end @spec cleanup(t(), any()) :: t() def cleanup(agent, cur_state) def cleanup(%GraphAgent{cleanup_fn: nil} = agent, _cur_state) do agent end def cleanup(%GraphAgent{cleanup_fn: cleanup_fn} = agent, cur_state) do cleanup_fn.(cur_state) agent end end