Raxol.Agent.ToolPolicy (Raxol Agent v2.6.0)

Copy Markdown View Source

Composable authorizers for the LLM tool-call path.

A tool authorizer is a (action_module, params, context) -> :ok | {:deny, reason} function placed in the agent context under :tool_authorizer. Raxol.Agent.Action.ToolConverter.dispatch_tool_call/3 consults it before invoking the Action, so a prompt-injected LLM cannot drive a sensitive tool (e.g. a payment Action) just by emitting a tool call. Absent, tool calls are allowed (backward compatible) -- set one to enforce.

context = %{tool_authorizer: Raxol.Agent.ToolPolicy.denylist(["payment_execute_xochi_intent"])}
Raxol.Agent.Strategy.ReAct.execute(action_spec, state, Map.merge(base, context))

Authorizers compose with all/1 (deny if any denies).

Richer phase-aware policy (ALLOW/ASK/DENY) lives in Raxol.Agent.Authorization.Engine at the :tool_call phase; delegating to it from here is a follow-up.

Summary

Functions

Combine authorizers: the first {:deny, _} wins; otherwise :ok.

Allow every tool call.

Allow only Actions whose tool name is in names; deny the rest.

Deny every tool call.

Deny Actions whose metadata marks them sensitive: true (fund-movers like the payment Actions); allow the rest. This is the default policy applied when no :tool_authorizer is set, so a prompt-injected LLM cannot drive a sensitive tool unless the agent explicitly opts in (e.g. with allow_all/0).

Deny Actions whose tool name is in names; allow the rest.

Types

authorizer()

@type authorizer() :: (module(), map(), map() -> :ok | {:deny, term()})

Functions

all(authorizers)

@spec all([authorizer()]) :: authorizer()

Combine authorizers: the first {:deny, _} wins; otherwise :ok.

allow_all()

@spec allow_all() :: authorizer()

Allow every tool call.

allowlist(names)

@spec allowlist([String.t()]) :: authorizer()

Allow only Actions whose tool name is in names; deny the rest.

deny_all(reason \\ :tools_disabled)

@spec deny_all(term()) :: authorizer()

Deny every tool call.

deny_sensitive()

@spec deny_sensitive() :: authorizer()

Deny Actions whose metadata marks them sensitive: true (fund-movers like the payment Actions); allow the rest. This is the default policy applied when no :tool_authorizer is set, so a prompt-injected LLM cannot drive a sensitive tool unless the agent explicitly opts in (e.g. with allow_all/0).

denylist(names)

@spec denylist([String.t()]) :: authorizer()

Deny Actions whose tool name is in names; allow the rest.