# `LLMDB.Enrich`
[🔗](https://github.com/agentjido/llmdb/blob/main/lib/llm_db/engine/enrich.ex#L1)

Lightweight, deterministic enrichment of model data.

This module performs simple derivations and defaults, such as:
- Deriving model family from model ID
- Setting provider_model_id to id if not present
- Attaching optional llmfit sidecar metadata for matching Hugging Face models
- Copying native Claude reasoning metadata to Claude models hosted on
  Amazon Bedrock, Google Vertex AI and Azure
- Ensuring capability defaults are applied (handled by Zoi schemas)
- Removing limits that a reviewed overlay marks as unpublished

# `derive_family`

```elixir
@spec derive_family(String.t()) :: String.t() | nil
```

Derives the family name from a model ID using prefix logic.

Extracts family from model ID by splitting on "-" and taking all but the last segment.
Returns nil if the family cannot be reasonably derived.

## Examples

    iex> LLMDB.Enrich.derive_family("gpt-4o-mini")
    "gpt-4o"

    iex> LLMDB.Enrich.derive_family("claude-3-opus")
    "claude-3"

    iex> LLMDB.Enrich.derive_family("gemini-1.5-pro")
    "gemini-1.5"

    iex> LLMDB.Enrich.derive_family("single")
    nil

    iex> LLMDB.Enrich.derive_family("two-parts")
    "two"

# `enrich_model`

```elixir
@spec enrich_model(map()) :: map()
```

Enriches a single model map with derived and default values.

Sets the following fields if not already present:
- `family`: Derived from model ID
- `provider_model_id`: Set to model ID

Note: Capability defaults are handled automatically by Zoi schema validation.

## Examples

    iex> LLMDB.Enrich.enrich_model(%{id: "gpt-4o-mini", provider: :openai})
    %{id: "gpt-4o-mini", provider: :openai, family: "gpt-4o", provider_model_id: "gpt-4o-mini"}

    iex> LLMDB.Enrich.enrich_model(%{id: "claude-3-opus", provider: :anthropic, family: "claude-3-custom"})
    %{id: "claude-3-opus", provider: :anthropic, family: "claude-3-custom", provider_model_id: "claude-3-opus"}

    iex> LLMDB.Enrich.enrich_model(%{id: "model", provider: :openai, provider_model_id: "custom-id"})
    %{id: "model", provider: :openai, provider_model_id: "custom-id"}

# `enrich_models`

```elixir
@spec enrich_models([map()]) :: [map()]
```

Enriches a list of model maps.

Applies `enrich_model/1` to each model in the list.

## Examples

    iex> LLMDB.Enrich.enrich_models([
    ...>   %{id: "gpt-4o", provider: :openai},
    ...>   %{id: "claude-3-opus", provider: :anthropic}
    ...> ])
    [
      %{id: "gpt-4o", provider: :openai, family: "gpt", provider_model_id: "gpt-4o"},
      %{id: "claude-3-opus", provider: :anthropic, family: "claude-3", provider_model_id: "claude-3-opus"}
    ]

# `inherit_canonical_costs`

```elixir
@spec inherit_canonical_costs([map()]) :: [map()]
```

Propagates cost from canonical models to their dated variants.

For models with a date suffix (e.g., `gpt-4o-mini-2024-07-18`), if the model
has no cost, looks up the canonical model (e.g., `gpt-4o-mini`) from the same
provider and copies its cost.

Models that already have a cost are left unchanged.

## Examples

    iex> models = [
    ...>   %{id: "gpt-4o-mini", provider: :openai, cost: %{input: 0.15, output: 0.6}},
    ...>   %{id: "gpt-4o-mini-2024-07-18", provider: :openai}
    ...> ]
    iex> [_, dated] = LLMDB.Enrich.inherit_canonical_costs(models)
    iex> dated.cost
    %{input: 0.15, output: 0.6}

# `inherit_hosted_claude_reasoning`

```elixir
@spec inherit_hosted_claude_reasoning([map()]) :: [map()]
```

Copies native Claude reasoning metadata to hosted Claude models that lack it.

Amazon Bedrock, Google Vertex AI and Azure serve Claude with the Anthropic
Messages request body, so a hosted entry accepts the same thinking types and
effort levels as the native model named by its `canonical_model_id`.
Upstream sources usually publish only `reasoning.enabled` for hosted entries.

For a model hosted on Bedrock or Vertex AI, or one whose `wire_protocol` is
`anthropic_messages`, that links to an `anthropic/` canonical model, this
fills `capabilities.reasoning.thinking`, `capabilities.reasoning.effort` and
`extra.thinking_constraints` from the native model when the hosted entry has
none. Values the hosted entry already sets are kept, and entries whose
reasoning is explicitly disabled are left alone.

Routers that translate Claude into another request format, such as
OpenRouter, are not changed.

## Examples

    iex> models = [
    ...>   %{
    ...>     id: "claude-sonnet-5-5",
    ...>     provider: :anthropic,
    ...>     capabilities: %{reasoning: %{enabled: true, thinking: %{types: ["adaptive", "between_tools"]}}}
    ...>   },
    ...>   %{
    ...>     id: "global.anthropic.claude-sonnet-5-5",
    ...>     provider: :amazon_bedrock,
    ...>     capabilities: %{reasoning: %{enabled: true}},
    ...>     extra: %{canonical_model_id: "anthropic/claude-sonnet-5-5"}
    ...>   }
    ...> ]
    iex> [_native, hosted] = LLMDB.Enrich.inherit_hosted_claude_reasoning(models)
    iex> hosted.capabilities.reasoning.thinking.types
    ["adaptive", "between_tools"]

---

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