# `SuperPi.Extension`
[🔗](https://github.com/oleksandr/super-pi-beam/blob/v0.1.0/lib/super_pi/extension.ex#L1)

Unified 12-Hook Extension Pipeline behaviour (`09 - Data Flows and Extension Injection Points.md`).

Every callback is optional; modules that `use SuperPi.Extension` inherit pass-through default
implementations and can override only the hooks they need.

## The 12 Canonical Extension Hooks
1. `on_input/2` — Intercepts raw user text before turn creation (`:continue`, `{:transform, text, media}`, `:handled`).
2. `before_agent_start/2` — Mutates initial system prompt sections and active tool definitions before the run starts.
3. `before_compact/2` — Overrides or customizes context compaction (`:default`, `{:compacted, summary, data}`, `:cancel`).
4. `before_request/2` — Inspects/filters derived context messages in-memory right before provider serialization.
5. `before_provider_request/2` — Inspects/mutates the raw provider HTTP/JSON payload or aborts the call.
6. `after_response/2` — Inspects the completed assistant response and token usage before tool dispatch.
7. `before_tool/3` — Permission gate and input validator before a tool executes (`:allow`, `{:block, reason}`, `{:mutate_input, map}`).
8. `wrap_tool/4` — Higher-order middleware around tool execution (`next.(args)`).
9. `after_tool/4` — Post-processes 3-channel tool output (`output`, `structured_output`, `details`) before recording `pi.event`.
10. `after_tools/3` — Runs after a parallel tool batch settles (`:continue`, `{:steer, msg}`, `{:handoff, agent}`).
11. `on_yield/3` — Intercepts child task or external yield waits.
12. `after_run/2` — Verification and continuation gate when the assistant stops calling tools (`:accept` or `{:continue, follow_up_prompt}`).

# `context`

```elixir
@type context() :: map()
```

# `after_response`
*optional* 

```elixir
@callback after_response(assistant_msg :: map(), context()) :: {:ok, map()}
```

# `after_run`
*optional* 

```elixir
@callback after_run(run_summary :: map(), context()) :: :accept | {:continue, String.t()}
```

# `after_tool`
*optional* 

```elixir
@callback after_tool(tool_name :: String.t(), args :: map(), result :: map(), context()) ::
  {:ok, map()}
```

# `after_tools`
*optional* 

```elixir
@callback after_tools(batch_results :: [map()], context()) ::
  :continue | {:steer, String.t()} | {:handoff, map()} | :terminate
```

# `before_agent_start`
*optional* 

```elixir
@callback before_agent_start(agent_config :: map(), context()) :: {:ok, map()}
```

# `before_compact`
*optional* 

```elixir
@callback before_compact(compaction_req :: map(), context()) ::
  :default | {:compacted, String.t(), map()} | :cancel
```

# `before_provider_request`
*optional* 

```elixir
@callback before_provider_request(provider_payload :: map(), context()) ::
  {:ok, map()} | {:abort, term()}
```

# `before_request`
*optional* 

```elixir
@callback before_request(derived_context :: map(), context()) :: {:ok, map()}
```

# `before_tool`
*optional* 

```elixir
@callback before_tool(tool_name :: String.t(), args :: map(), context()) ::
  :allow | {:block, String.t()} | {:mutate_input, map()} | {:overwrite, map()}
```

# `on_input`
*optional* 

```elixir
@callback on_input(input :: String.t(), context()) ::
  :continue | {:transform, String.t(), list()} | :handled
```

# `on_yield`
*optional* 

```elixir
@callback on_yield(yield_info :: map(), context()) :: :ok
```

# `wrap_tool`
*optional* 

```elixir
@callback wrap_tool(
  tool_name :: String.t(),
  args :: map(),
  next :: (map() -&gt; map()),
  context()
) :: map()
```

# `run_after_response`

# `run_after_run`

# `run_after_tool`

# `run_after_tools`

# `run_before_agent_start`

# `run_before_compact`

# `run_before_provider_request`

# `run_before_request`

# `run_before_tool`

# `run_on_input`

# `run_wrap_tool`

---

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