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

Search provider adapters for `web_search`.

`web_search` is offered to the model only when a provider is configured and usable
(`configured/1`). A tool that always fails costs tokens on every request and teaches the model
to retry, so with no provider the tool does not exist. There is no fallback that scrapes a
search engine.

A provider is a module that implements this behaviour:

| Provider | Module | Needs |
|---|---|---|
| Brave Search | `SuperPi.Web.Search.Brave` | `api_key` or `BRAVE_API_KEY` |
| Tavily | `SuperPi.Web.Search.Tavily` | `api_key` or `TAVILY_API_KEY` |
| SearxNG | `SuperPi.Web.Search.SearxNG` | `base_url` or `SEARXNG_URL` |

## Configuration

The provider comes from the first of: the plugin option `search:`, `config :super_pi,
:web_search`, the environment variable `SUPER_PI_WEB_SEARCH` (`brave`, `tavily` or `searxng`).
A value is an atom or name (`:brave`), a module, or `{module_or_name, opts}`. Options are
`api_key`, `base_url` and `req_options` (merged into the Req call, for tests).

The endpoints are operator-configured and trusted, so they are not subject to
`SuperPi.Web.Policy` (a SearxNG instance on a private network is the normal case). Result
URLs are untrusted: the model still has to fetch them with `web_fetch`, which applies the policy.

# `result`

```elixir
@type result() :: %{title: String.t(), url: String.t(), snippet: String.t()}
```

# `configured?`

```elixir
@callback configured?(opts :: keyword()) :: boolean()
```

# `search`

```elixir
@callback search(query :: String.t(), max_results :: pos_integer(), opts :: keyword()) ::
  {:ok, [result()]} | {:error, String.t()}
```

# `configured`

```elixir
@spec configured(keyword()) :: {module(), keyword()} | nil
```

Resolves the provider for a web plugin's options: `{module, opts}`, or `nil` when none is
configured or the configured one lacks its key or URL.

# `resolve`

```elixir
@spec resolve(term()) :: {module(), keyword()} | nil
```

Resolves a provider spec. See the moduledoc for the accepted forms.

# `run`

```elixir
@spec run({module(), keyword()}, String.t(), pos_integer()) ::
  {:ok, [result()]} | {:error, String.t()}
```

Runs a search through a resolved provider. Never raises.

---

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