# `Agentic.LLM.Model`

Shared struct describing a single LLM model.

Providers populate `default_models/0` with these. The `Agentic.LLM.Catalog`
GenServer merges static, discovered, and user-overridden model lists.

Fields:

  * `:id` — provider-local model id (e.g. `"claude-opus-4-20250514"`).
  * `:provider` — atom id of the provider module (e.g. `:anthropic`).
  * `:label` — human-readable label for UI.
  * `:context_window` — input token budget.
  * `:max_output_tokens` — generation budget.
  * `:cost` — map `%{input: ..., output: ..., cache_read: ..., cache_write: ...}`
    with prices in USD per 1M tokens.
  * `:capabilities` — `MapSet` of capability tags. Tags describe what
    the model is genuinely good at; specialty models carry only their
    specialty tag so they are never selected for general chat by
    mistake. Recognised tags:

      * `:chat` — text-in/text-out conversational dialog. Implies the
        model is appropriate for plain conversation. Specialty
        models (image generation, audio output, embeddings) do not
        get `:chat`.
      * `:tools` — supports function calling. Only set on models
        that are also `:chat` capable.
      * `:vision` — accepts image input.
      * `:audio_in` — accepts audio input.
      * `:audio_out` — generates audio output (specialty).
      * `:image_gen` — generates image output (specialty).
      * `:embeddings` — generates embeddings (specialty).
      * `:reasoning` — supports extended thinking / reasoning.
      * `:prompt_caching` — supports prompt caching (Anthropic).
      * `:json_mode` — supports structured-output mode (OpenAI).
      * `:free` — zero per-token cost.
  * `:tier_hint` — provider-suggested tier (`:primary`, `:lightweight`,
    or `nil`).
  * `:source` — where the entry came from (`:static`, `:discovered`,
    `:user_config`).
  * `:endpoints` — list of provider endpoint maps from the OpenRouter
    `/endpoints` API (provider-specific pricing, uptime, latency,
    throughput). `nil` when not fetched.
  * `:canonical_id` — provider-agnostic identity for the underlying
    model weights. Multiple `(provider, model_id)` rows can map to the
    same `canonical_id` (e.g. `claude-sonnet-4` is reachable via
    Anthropic direct, Claude Code CLI, and OpenRouter). Resolved by
    `Agentic.LLM.Canonical.for_model/2` — providers should not
    hardcode it. `nil` is permitted; the catalog backfills it on
    insert. Capabilities remain per-pathway: a model that's reached
    via the Claude Code CLI does not necessarily expose every feature
    of the same model reached via the direct API.

# `capability`

```elixir
@type capability() :: atom()
```

# `cost`

```elixir
@type cost() :: %{
  :input =&gt; float(),
  :output =&gt; float(),
  optional(:cache_read) =&gt; float(),
  optional(:cache_write) =&gt; float()
}
```

# `t`

```elixir
@type t() :: %Agentic.LLM.Model{
  canonical_id: String.t() | nil,
  capabilities: MapSet.t(),
  context_window: pos_integer() | nil,
  cost: cost() | nil,
  endpoints: [map()] | nil,
  id: String.t(),
  label: String.t() | nil,
  max_output_tokens: pos_integer() | nil,
  provider: atom(),
  source: :static | :discovered | :user_config,
  tier_hint: :primary | :lightweight | nil
}
```

---

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