View Source AI.Tools behaviour (fnord v0.5.8)

This module defines the behaviour for tool calls. Defining a new tool requires implementing the spec/0 and call/2 functions.

The spec/0 function should return a map that describes the tool's capabilities and arguments, using a map to represent the OpenAPI spec.

The call/2 function generates the tool call response. It accepts the requesting AI.Completion's struct and a map derived from the parsed JSON provided by the agent, containing the tool call arguments. Note that, because the arguments are parsed from JSON, the keys will all be strings. Whether those are converted to symbols is between the tool implementation and the code it calls. What happens behind closed APIs is none of MY business.

Skeleton Implementation

defmodule AI.Tools.MyNewTool do
  @behaviour AI.Tools

  @impl AI.Tools
  def ui_note_on_request(_args) do
    {"Doing something", "This tool is doing something."}
  end

  @impl AI.Tools
  def ui_note_on_result(_args, _result) do
    {"Did something", "This tool did something."}
  end

  @impl AI.Tools
  def read_args(args) do
    {:ok, args}
  end

  @impl AI.Tools
  def spec() do
    %{
      type: "function",
      function: %{
        name: "something_tool",
        description: "This tool does something.",
        strict: true,
        parameters: %{
          additionalProperties: false,
          type: "object",
          required: ["thing"],
          properties: %{
            thing: %{
              type: "string",
              description: "The thing to do."
            }
          }
        }
      }
    }
  end

  @impl AI.Tools
  def call(_completion, args) do
    {:ok, "IMPLEMENT ME"}
  end
end

Summary

Callbacks

Calls the tool with the provided arguments and returns the response as an :ok tuple.

Reads the arguments and returns a map of the arguments if they are valid. This is used to validate args before the tool is called. The result is what is passed to call/2, ui_note_on_request/1, and ui_note_on_result/2.

Returns the OpenAPI spec for the tool as an elixir map.

Return either a short string or a string tuple of label + detail to be displayed when the tool is called.

Return either a short string or a string tuple of label + detail to be displayed when the tool call is successful.

Functions

Types

args_error()

@type args_error() ::
  {:error, :missing_argument, String.t()}
  | {:error, :invalid_argument, String.t()}

Callbacks

call(completion, args)

@callback call(completion :: AI.Completion.t(), args :: map()) ::
  :ok | {:ok, any()} | {:error, any()} | :error

Calls the tool with the provided arguments and returns the response as an :ok tuple.

read_args(args)

@callback read_args(args :: map()) :: {:ok, map()} | args_error()

Reads the arguments and returns a map of the arguments if they are valid. This is used to validate args before the tool is called. The result is what is passed to call/2, ui_note_on_request/1, and ui_note_on_result/2.

spec()

@callback spec() :: map()

Returns the OpenAPI spec for the tool as an elixir map.

ui_note_on_request(args)

@callback ui_note_on_request(args :: map()) :: {String.t(), String.t()} | String.t() | nil

Return either a short string or a string tuple of label + detail to be displayed when the tool is called.

ui_note_on_result(args, result)

@callback ui_note_on_result(args :: map(), result :: any()) ::
  {String.t(), String.t()} | String.t() | nil

Return either a short string or a string tuple of label + detail to be displayed when the tool call is successful.

Functions

get_entry(file)

get_entry(project, file)

get_file_contents(file)

get_file_contents(project, file)

get_project()

on_tool_request(tool, args, tools \\ %{"answers_tool" => AI.Tools.Answers, "file_contents_tool" => AI.Tools.File.Contents, "file_info_tool" => AI.Tools.File.Info, "file_list_tool" => AI.Tools.File.List, "file_outline_tool" => AI.Tools.File.Outline, "file_search_tool" => AI.Tools.File.Search, "file_spelunker_tool" => AI.Tools.File.Spelunker, "git_diff_branch_tool" => AI.Tools.Git.DiffBranch, "git_grep_tool" => AI.Tools.Git.Grep, "git_list_branches_tool" => AI.Tools.Git.ListBranches, "git_log_tool" => AI.Tools.Git.Log, "git_pickaxe_tool" => AI.Tools.Git.Pickaxe, "git_show_tool" => AI.Tools.Git.Show, "notes_save_tool" => AI.Tools.Notes.Save, "notes_search_tool" => AI.Tools.Notes.Search, "strategies_search_tool" => AI.Tools.Strategies.Search})

on_tool_result(tool, args, result, tools \\ %{"answers_tool" => AI.Tools.Answers, "file_contents_tool" => AI.Tools.File.Contents, "file_info_tool" => AI.Tools.File.Info, "file_list_tool" => AI.Tools.File.List, "file_outline_tool" => AI.Tools.File.Outline, "file_search_tool" => AI.Tools.File.Search, "file_spelunker_tool" => AI.Tools.File.Spelunker, "git_diff_branch_tool" => AI.Tools.Git.DiffBranch, "git_grep_tool" => AI.Tools.Git.Grep, "git_list_branches_tool" => AI.Tools.Git.ListBranches, "git_log_tool" => AI.Tools.Git.Log, "git_pickaxe_tool" => AI.Tools.Git.Pickaxe, "git_show_tool" => AI.Tools.Git.Show, "notes_save_tool" => AI.Tools.Notes.Save, "notes_search_tool" => AI.Tools.Notes.Search, "strategies_search_tool" => AI.Tools.Strategies.Search})

perform_tool_call(state, tool, args, tools \\ %{"answers_tool" => AI.Tools.Answers, "file_contents_tool" => AI.Tools.File.Contents, "file_info_tool" => AI.Tools.File.Info, "file_list_tool" => AI.Tools.File.List, "file_outline_tool" => AI.Tools.File.Outline, "file_search_tool" => AI.Tools.File.Search, "file_spelunker_tool" => AI.Tools.File.Spelunker, "git_diff_branch_tool" => AI.Tools.Git.DiffBranch, "git_grep_tool" => AI.Tools.Git.Grep, "git_list_branches_tool" => AI.Tools.Git.ListBranches, "git_log_tool" => AI.Tools.Git.Log, "git_pickaxe_tool" => AI.Tools.Git.Pickaxe, "git_show_tool" => AI.Tools.Git.Show, "notes_save_tool" => AI.Tools.Notes.Save, "notes_search_tool" => AI.Tools.Notes.Search, "strategies_search_tool" => AI.Tools.Strategies.Search})

required_arg_error(key)

tool_module(tool, tools \\ %{"answers_tool" => AI.Tools.Answers, "file_contents_tool" => AI.Tools.File.Contents, "file_info_tool" => AI.Tools.File.Info, "file_list_tool" => AI.Tools.File.List, "file_outline_tool" => AI.Tools.File.Outline, "file_search_tool" => AI.Tools.File.Search, "file_spelunker_tool" => AI.Tools.File.Spelunker, "git_diff_branch_tool" => AI.Tools.Git.DiffBranch, "git_grep_tool" => AI.Tools.Git.Grep, "git_list_branches_tool" => AI.Tools.Git.ListBranches, "git_log_tool" => AI.Tools.Git.Log, "git_pickaxe_tool" => AI.Tools.Git.Pickaxe, "git_show_tool" => AI.Tools.Git.Show, "notes_save_tool" => AI.Tools.Notes.Save, "notes_search_tool" => AI.Tools.Notes.Search, "strategies_search_tool" => AI.Tools.Strategies.Search})

tool_spec(tool, tools \\ %{"answers_tool" => AI.Tools.Answers, "file_contents_tool" => AI.Tools.File.Contents, "file_info_tool" => AI.Tools.File.Info, "file_list_tool" => AI.Tools.File.List, "file_outline_tool" => AI.Tools.File.Outline, "file_search_tool" => AI.Tools.File.Search, "file_spelunker_tool" => AI.Tools.File.Spelunker, "git_diff_branch_tool" => AI.Tools.Git.DiffBranch, "git_grep_tool" => AI.Tools.Git.Grep, "git_list_branches_tool" => AI.Tools.Git.ListBranches, "git_log_tool" => AI.Tools.Git.Log, "git_pickaxe_tool" => AI.Tools.Git.Pickaxe, "git_show_tool" => AI.Tools.Git.Show, "notes_save_tool" => AI.Tools.Notes.Save, "notes_search_tool" => AI.Tools.Notes.Search, "strategies_search_tool" => AI.Tools.Strategies.Search})

tool_spec!(tool, tools \\ %{"answers_tool" => AI.Tools.Answers, "file_contents_tool" => AI.Tools.File.Contents, "file_info_tool" => AI.Tools.File.Info, "file_list_tool" => AI.Tools.File.List, "file_outline_tool" => AI.Tools.File.Outline, "file_search_tool" => AI.Tools.File.Search, "file_spelunker_tool" => AI.Tools.File.Spelunker, "git_diff_branch_tool" => AI.Tools.Git.DiffBranch, "git_grep_tool" => AI.Tools.Git.Grep, "git_list_branches_tool" => AI.Tools.Git.ListBranches, "git_log_tool" => AI.Tools.Git.Log, "git_pickaxe_tool" => AI.Tools.Git.Pickaxe, "git_show_tool" => AI.Tools.Git.Show, "notes_save_tool" => AI.Tools.Notes.Save, "notes_search_tool" => AI.Tools.Notes.Search, "strategies_search_tool" => AI.Tools.Strategies.Search})

validate_required_args(tool, args, tools \\ %{"answers_tool" => AI.Tools.Answers, "file_contents_tool" => AI.Tools.File.Contents, "file_info_tool" => AI.Tools.File.Info, "file_list_tool" => AI.Tools.File.List, "file_outline_tool" => AI.Tools.File.Outline, "file_search_tool" => AI.Tools.File.Search, "file_spelunker_tool" => AI.Tools.File.Spelunker, "git_diff_branch_tool" => AI.Tools.Git.DiffBranch, "git_grep_tool" => AI.Tools.Git.Grep, "git_list_branches_tool" => AI.Tools.Git.ListBranches, "git_log_tool" => AI.Tools.Git.Log, "git_pickaxe_tool" => AI.Tools.Git.Pickaxe, "git_show_tool" => AI.Tools.Git.Show, "notes_save_tool" => AI.Tools.Notes.Save, "notes_search_tool" => AI.Tools.Notes.Search, "strategies_search_tool" => AI.Tools.Strategies.Search})

with_args(tool, args, fun)