lib/vnext_genai/nodes/tool.ex

defmodule GenAI.Tool do
  @moduledoc """
  Represents a function that can be called by the model.
  """
  @vsn 1.0

  require GenAI.Records.Directive
  import GenAI.Records.Directive

  use GenAI.Graph.NodeBehaviour
  @derive GenAI.Graph.NodeProtocol
  # @derive GenAI.Thread.SessionProtocol
  defnodestruct(parameters: nil)
  defnodetype(parameters: term)

  def apply_node_directives(this, graph_link, graph_container, session, context, options)

  def apply_node_directives(this, _, _, session, context, options) do
    entry = tool_entry(tool: this.name)
    directive = GenAI.Session.State.Directive.static(entry, this, {:node, this.id})
    GenAI.Thread.Session.append_directive(session, directive, context, options)
  end

  @doc """
  Extract function from json.
  """
  def from_json(json_string) when is_bitstring(json_string) do
    with {:ok, json} <- Jason.decode(json_string) do
      do_from_json(json)
    end
  end

  @doc """
  Extract function from yaml.
  """
  def from_yaml(yaml_string) when is_bitstring(yaml_string) do
    with {:ok, json} <- YamlElixir.read_from_string(yaml_string) do
      do_from_json(json)
    end
  end

  defp do_from_json(%{"type" => "function", "function" => json}) do
    do_from_json(json)
  end

  defp do_from_json(%{"name" => _} = json) do
    # parameters is json a standard object json schema entry so use it to build a map of parameters one implemented.
    parameters =
      with {:ok, x} <- json["parameters"] && GenAI.Tool.Schema.Type.from_json(json["parameters"]) do
        x
      end

    {:ok,
     %GenAI.Tool{
       name: json["name"],
       description: json["description"],
       parameters: parameters
     }}
  end
  
  
  def inspect_custom_details(subject, opts) do
    ["parameters:", Inspect.Algebra.to_doc(subject.parameters, opts), ", "]
  end
  
  defimpl GenAI.ToolProtocol do
    def name(subject), do: {:ok, subject.name}
  end
end