# `ADK.Policy`
[🔗](https://github.com/zeroasterisk/adk-elixir/blob/main/lib/adk/policy.ex#L1)

Policy behaviour for agent governance — tool access control, content filtering, etc.

Policies are checked at key points in the agent pipeline:

- `authorize_tool/3` — before a tool executes, decides allow/deny
- `filter_input/2` — filters user input before it reaches the LLM
- `filter_output/2` — filters agent output events before they're returned

## Usage

    defmodule MyPolicy do
      @behaviour ADK.Policy

      @impl true
      def authorize_tool(%{name: "dangerous_tool"}, _args, _ctx), do: {:deny, "forbidden"}
      def authorize_tool(_tool, _args, _ctx), do: :allow

      @impl true
      def filter_input(content, _ctx), do: {:cont, content}

      @impl true
      def filter_output(events, _ctx), do: events
    end

    # Pass policies to Runner.run/5
    ADK.Runner.run(runner, user_id, session_id, message, policies: [MyPolicy])

## Composition

Multiple policies are composed as a chain of responsibility:

- `authorize_tool` — first `:deny` wins; all must allow
- `filter_input` — chained sequentially; first `{:halt, events}` short-circuits
- `filter_output` — chained sequentially, each transforms the events

# `tool_decision`

```elixir
@type tool_decision() :: :allow | {:deny, String.t()}
```

# `authorize_tool`
*optional* 

```elixir
@callback authorize_tool(tool :: map(), args :: map(), ctx :: ADK.Context.t()) ::
  tool_decision()
```

Authorize a tool call. Return `:allow` or `{:deny, reason}`.

# `filter_input`
*optional* 

```elixir
@callback filter_input(content :: map(), ctx :: ADK.Context.t()) ::
  {:cont, map()} | {:halt, [ADK.Event.t()]}
```

Filter user input before the LLM sees it. Return `{:cont, content}` or `{:halt, [ADK.Event.t()]}`.

# `filter_output`
*optional* 

```elixir
@callback filter_output([ADK.Event.t()], ADK.Context.t()) :: [ADK.Event.t()]
```

Filter output events before they're returned. Returns transformed events.

# `check_tool_authorization`

```elixir
@spec check_tool_authorization([module() | struct()], map(), map(), ADK.Context.t()) ::
  tool_decision()
```

Run `authorize_tool` across a list of policies. First deny wins.

Supports both module-based policies (atoms implementing the `ADK.Policy` behaviour)
and struct-based policies (e.g., `%ADK.Policy.HumanApproval{}`). Struct policies
must implement a `check/4` function for per-instance configuration.

# `run_input_filters`

```elixir
@spec run_input_filters([module()], map(), ADK.Context.t()) ::
  {:cont, map()} | {:halt, [ADK.Event.t()]}
```

Run `filter_input` across a list of policies. First halt wins; otherwise content is threaded.

# `run_output_filters`

```elixir
@spec run_output_filters([module()], [ADK.Event.t()], ADK.Context.t()) :: [
  ADK.Event.t()
]
```

Run `filter_output` across a list of policies, threading events through each.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
