ALLM.Tool (allm v0.3.0)

Copy Markdown View Source

A tool the model may call. See spec §5.2 and §15.

Layer A — the struct itself is pure data (:name, :description, :schema, :metadata, :manual are all serializable), but :handler may be an anonymous function. A tool with a fn handler is not safe to persist via :erlang.term_to_binary/1; persist either :handler | nil and re-attach at load time, or use a {Module, :function} tuple.

Per-tool manual mode (Phase 18)

Setting manual: true declares this tool will not be auto-executed by ALLM.chat/3 even when the call uses mode: :auto. When the assistant emits a tool call for a manual: true tool, the chat orchestrator halts the loop with halted_reason: :manual_tool_calls and surfaces the call in metadata.manual_tool_calls. The caller resolves the tool result either via ALLM.Session.submit_tool_result/3 (when running through the Session API) or by appending a :tool message to the thread and re-issuing chat/3 (raw stateless flow).

Default: false — the tool is auto-executed under mode: :auto (today's behaviour). The flag is silent under mode: :manual whole-loop manual (spec §12); the whole-loop short-circuit fires before the per-tool partition runs.

See spec §12.4 (per-tool manual) and Phase 18 design.

Summary

Types

Tool handler — called with parsed arguments (arity 1) or with arguments plus a caller-supplied context keyword list (arity 2).

Legal returns from a tool handler. See spec §5.2 and §12.3 (ask-user).

t()

Functions

Build a %Tool{} from keyword opts.

Types

handler()

@type handler() ::
  (map() -> handler_result()) | (map(), keyword() -> handler_result())

Tool handler — called with parsed arguments (arity 1) or with arguments plus a caller-supplied context keyword list (arity 2).

handler_result()

@type handler_result() ::
  {:ok, term()}
  | {:error, term()}
  | {:ask_user, String.t()}
  | {:ask_user, String.t(), keyword()}
  | {:halt, atom(), term()}

Legal returns from a tool handler. See spec §5.2 and §12.3 (ask-user).

schema()

@type schema() :: map()

t()

@type t() :: %ALLM.Tool{
  description: String.t(),
  handler: handler() | nil,
  manual: boolean(),
  metadata: map(),
  name: String.t(),
  schema: schema()
}

Functions

new(opts)

@spec new(keyword()) :: t()

Build a %Tool{} from keyword opts.

:name, :description, and :schema are required; omitting any raises ArgumentError via struct!/2. :handler is optional — a tool may be declared without a handler when the caller handles tool calls manually.

:manual is optional and defaults to false. It MUST be a boolean — passing :manual with a non-boolean value (including nil) raises ArgumentError. The defstruct default protects against omission, but struct!/2 accepts an explicit nil (silently overwriting the default), so this constructor adds an explicit guard.

Examples

iex> tool = ALLM.Tool.new(name: "weather", description: "weather by city", schema: %{"type" => "object"})
iex> tool.name
"weather"
iex> tool.handler
nil
iex> tool.manual
false

iex> tool = ALLM.Tool.new(name: "charge", description: "charge a card", schema: %{"type" => "object"}, manual: true)
iex> tool.manual
true