# `Planck.AI.Config`
[🔗](https://github.com/alexdesousa/planck/blob/v0.2.2/lib/planck/ai/config.ex#L1)

Converts model configuration into `Planck.AI.Model` structs.

The entry point is `from_config/2`, which accepts the v0.1.6 config format:
a `providers` map (user-keyed) and a `models` list where each entry references
a provider by key.

## Format

    providers = %{
      "anthropic" => %{"type" => "anthropic"},
      "nvidia"    => %{"type" => "openai", "base_url" => "https://integrate.api.nvidia.com/v1", "identifier" => "NVIDIA"},
      "local"     => %{"type" => "openai", "base_url" => "http://localhost:11434", "has_api_key" => false}
    }

    models = [
      %{"id" => "sonnet",   "model" => "claude-sonnet-4-6",             "provider" => "anthropic"},
      %{"id" => "llama70b", "model" => "meta/llama-3.3-70b-instruct",   "provider" => "nvidia"},
      %{"id" => "llama3.2", "model" => "llama3.2",                      "provider" => "local"}
    ]

    models = Planck.AI.Config.from_config(providers, models)

# `from_config`

```elixir
@spec from_config(%{required(String.t()) =&gt; map()}, [map()]) :: [Planck.AI.Model.t()]
```

Builds a list of `Model` structs from the v0.1.6 config format, which separates
provider entries (keyed map) from model entries (list).

Each model entry must reference a key in `providers` via its `"provider"` field.
Invalid entries are skipped with a warning; the rest are returned.

# `sanitize_identifier`

```elixir
@spec sanitize_identifier(String.t()) :: {:ok, String.t()} | :error
```

Normalizes a user-supplied identifier into a valid env-var tag: upcased,
characters outside `A-Z0-9` replaced with `_`, and leading non-letter
characters stripped (env var names must start with a letter).

Used both when loading config (so a typo'd identifier degrades to a
usable tag instead of dropping the model) and when writing config via
`Planck.Headless.configure_provider/1` (so the persisted identifier and
the `.env` key it derives always agree).

Returns `:error` only when nothing but non-letters remains (e.g. `"3.6"`).

    iex> Planck.AI.Config.sanitize_identifier("Qwen 3.6 27B")
    {:ok, "QWEN_3_6_27B"}

    iex> Planck.AI.Config.sanitize_identifier("nvidia")
    {:ok, "NVIDIA"}

---

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