Normandy.Tools.Toolset (normandy v2.2.0)

View Source

The tools an agent can call, by name.

Each tool is a struct holding the tool's own configuration. register/3 indexes it by its name and takes options that belong to the registration (see register/3). to_tool_schemas/1 produces the tool definitions sent to the model.

In the examples, calculator, string_tool, tool1 and tool2 stand for structs of modules that use Normandy.Tool, each named after its variable.

Summary

Types

t()

A toolset. tools maps each tool's name to its registration: an internal struct holding the tool and the options register/3 took, not the tool itself. Read the tools with list/1 and fetch/2, not from the map.

Functions

Returns the number of tools in the toolset.

The tool registered as tool_name: {:ok, tool}, or :error.

The tool registered as tool_name. Raises Normandy.ToolNotFoundError (naming the registered tools) when there is none.

Checks if a tool with the given name exists in the toolset.

Returns a list of all registered tools.

Returns a list of all tool names in the toolset.

The :max_result_chars tool_name was registered with: {:ok, chars}, {:ok, nil} (no cap), or :error when it was registered without one (the agent's :max_tool_result_chars applies) or is not registered.

An empty toolset.

A toolset holding tools, registered in order. An entry is a tool, or {tool, opts} to pass opts to register/3.

Registers tool under its name.

The :timeout tool_name was registered with, or nil when it was registered without one (or is not registered).

Generates a list of tool schemas for LLM consumption.

Removes a tool from the toolset by name.

Whether name is a tool name the API accepts: 1 to 64 letters, digits, underscores and dashes. register/3 raises on any other name.

Types

t()

@type t() :: %Normandy.Tools.Toolset{tools: %{required(String.t()) => struct()}}

A toolset. tools maps each tool's name to its registration: an internal struct holding the tool and the options register/3 took, not the tool itself. Read the tools with list/1 and fetch/2, not from the map.

Functions

count(toolset)

@spec count(t()) :: non_neg_integer()

Returns the number of tools in the toolset.

Examples

toolset = Normandy.Tools.Toolset.new([tool1, tool2])
Normandy.Tools.Toolset.count(toolset)
#=> 2

fetch(toolset, tool_name)

@spec fetch(t(), String.t()) :: {:ok, struct()} | :error

The tool registered as tool_name: {:ok, tool}, or :error.

fetch!(toolset, tool_name)

@spec fetch!(t(), String.t()) :: struct()

The tool registered as tool_name. Raises Normandy.ToolNotFoundError (naming the registered tools) when there is none.

has_tool?(toolset, tool_name)

@spec has_tool?(t(), String.t()) :: boolean()

Checks if a tool with the given name exists in the toolset.

Examples

toolset = Normandy.Tools.Toolset.new([calculator])
Normandy.Tools.Toolset.has_tool?(toolset, "calculator")
#=> true

Normandy.Tools.Toolset.has_tool?(toolset, "nonexistent")
#=> false

list(toolset)

@spec list(t()) :: [struct()]

Returns a list of all registered tools.

Examples

toolset = Normandy.Tools.Toolset.new([tool1, tool2])
Normandy.Tools.Toolset.list(toolset)
#=> [tool1, tool2]

list_names(toolset)

@spec list_names(t()) :: [String.t()]

Returns a list of all tool names in the toolset.

Examples

toolset = Normandy.Tools.Toolset.new([calculator])
Normandy.Tools.Toolset.list_names(toolset)
#=> ["calculator"]

max_result_chars(toolset, tool_name)

@spec max_result_chars(t(), String.t()) :: {:ok, pos_integer() | nil} | :error

The :max_result_chars tool_name was registered with: {:ok, chars}, {:ok, nil} (no cap), or :error when it was registered without one (the agent's :max_tool_result_chars applies) or is not registered.

new()

@spec new() :: t()

An empty toolset.

new(tools)

@spec new([struct() | {struct(), keyword()}]) :: t()

A toolset holding tools, registered in order. An entry is a tool, or {tool, opts} to pass opts to register/3.

Normandy.Tools.Toolset.new([%Search{}, {%Search{index: "b"}, replace: true}])

register(toolset, tool, opts \\ [])

@spec register(t(), struct(), keyword()) :: t()

Registers tool under its name.

The name must be 1 to 64 letters, digits, underscores or dashes (what the API accepts); anything else raises ArgumentError here rather than as a 400 on the first request. Registering a second tool with the same name raises ArgumentError unless replace: true. A struct whose module does not implement Normandy.Tool (a 1.x tool) raises ArgumentError naming the module. An unknown or mistyped option raises ArgumentError naming it.

Options

  • :timeout (pos_integer/0) - Milliseconds a call to this tool may run before it fails with a timeout. Without it, Normandy.Tools.Executor.default_timeout/0 (30_000).

  • :max_result_chars (pos_integer/0 or nil) - The longest result of this tool, in characters (graphemes), the model sees; nil = no cap. Without it, the agent's :max_tool_result_chars.

  • :replace (boolean/0) - Replace a tool already registered under the same name instead of raising. The default value is false.

timeout(toolset, tool_name)

@spec timeout(t(), String.t()) :: pos_integer() | nil

The :timeout tool_name was registered with, or nil when it was registered without one (or is not registered).

to_tool_schemas(toolset)

@spec to_tool_schemas(t()) :: [map()]

Generates a list of tool schemas for LLM consumption.

Returns a list of maps containing tool metadata (name, description, schema), and :native for a tool with a provider-defined type (Normandy.Tool.native_definition/1).

Examples

toolset = Normandy.Tools.Toolset.new([calculator])
Normandy.Tools.Toolset.to_tool_schemas(toolset)
#=> [
#     %{
#       name: "calculator",
#       description: "Performs arithmetic operations",
#       input_schema: %{type: "object", ...}
#     }
#   ]

unregister(toolset, tool_name)

@spec unregister(t(), String.t()) :: t()

Removes a tool from the toolset by name.

Examples

toolset = Normandy.Tools.Toolset.new([calculator])
Normandy.Tools.Toolset.unregister(toolset, "calculator")
#=> %Normandy.Tools.Toolset{tools: %{}}

valid_name?(name)

@spec valid_name?(term()) :: boolean()

Whether name is a tool name the API accepts: 1 to 64 letters, digits, underscores and dashes. register/3 raises on any other name.