Legion.Tool behaviour (Legion v0.6.0)

View Source

use Legion.Tool to mark a module as a tool available to agents.

By default, description/0 returns the module's source code so the LLM knows what functions are available. An agent running with tool_docs: :on_demand (see Legion.Agent) first sees only each tool's summary/0, one sentence, and reads the full description with Help.help(Name) when it needs it.

Overridable

  • description/0 - override to return a hand-written summary instead of the source code. Defaults to the module's source code.
  • description/1 - like description/0, but receives the active sandbox module, for tools whose usage differs by generated language. Preferred over description/0 when defined.
  • summary/0 - override to return the one sentence that stands for the tool in the tool list under tool_docs: :on_demand. Defaults to the first sentence of the @moduledoc, else of a hand-written description/0, else the module's short name. The example below has no @moduledoc, so its summary is WeatherTool - fetches current weather data. Mark an override @impl Legion.Tool: an unmarked summary/0, perhaps a tool function that was there first, gets a compile-time warning, since Legion takes it over and Lua code cannot call it.
  • extra_allowed_modules/0 - override to return additional modules that the sandbox should alias and permit when this tool is available. Defaults to []. Useful for tools like Legion.Tools.AgentTool that dispatch to other modules the agent needs to reference by name.
  • mcp?/0 - override to return false to leave the tool out when the agent is served over Legion.MCP.Server, where an outside caller writes the code. Defaults to true.

Example

defmodule MyApp.WeatherTool do
  use Legion.Tool

  def description do
    """
    WeatherTool - fetches current weather data.

    ## Functions
    - `current(city)` - returns weather JSON for the given city name.
    """
  end

  @doc "Returns current weather for a city."
  def current(city) do
    Req.get!("https://wttr.in/#{city}?format=j1").body
  end
end

External modules as tools

A module that does not use Legion.Tool (e.g. Req) can still be listed as a tool if its source code is registered at compile time, so the LLM can read what it offers:

config :legion, extra_source_modules: [Req]

Summary

Callbacks

Description of the tool shown to the LLM. Defaults to the module's source code.

Description of the tool for the given sandbox, shown to the LLM. Preferred over description/0 when defined, so a tool can tailor its usage notes to the generated language.

Whether Legion.MCP.Server serves the tool. Defaults to true.

One sentence that stands for the tool in the tool list under tool_docs: :on_demand. Defaults to the first sentence of the @moduledoc, else of a hand-written description/0, else the module's short name.

Callbacks

description()

@callback description() :: String.t()

Description of the tool shown to the LLM. Defaults to the module's source code.

description(sandbox)

(optional)
@callback description(sandbox :: module()) :: String.t()

Description of the tool for the given sandbox, shown to the LLM. Preferred over description/0 when defined, so a tool can tailor its usage notes to the generated language.

extra_allowed_modules()

@callback extra_allowed_modules() :: [module()]

mcp?()

@callback mcp?() :: boolean()

Whether Legion.MCP.Server serves the tool. Defaults to true.

summary()

@callback summary() :: String.t()

One sentence that stands for the tool in the tool list under tool_docs: :on_demand. Defaults to the first sentence of the @moduledoc, else of a hand-written description/0, else the module's short name.