# `CMDC.Config`
[🔗](https://github.com/tupleyun/cmdc/blob/v0.5.2/lib/cmdc/config.ex#L1)

CMDC 会话的类型化配置 struct。

通过 `CMDC.Config.new/1` 构建一次，在整个系统中传递。
所有字段有已知类型和合理默认值，不硬编码任何领域逻辑。

## 优先级（高者优先）

1. 传给 `new/1` 的会话覆盖
2. Application env — `config :cmdc, key: value`
3. 内置默认值

## 多 Provider 路由配置示例

    config :cmdc,
      default_model: "anthropic:claude-sonnet-4-5",
      providers: [
        {CMDC.Provider, [
          api_key: "sk-ant-xxx",
          base_url: "https://api.anthropic.com",
          models: ~r/^claude-/
        ]},
        {CMDC.Provider, [
          api_key: "sk-openai-yyy",
          models: :default
        ]}
      ]

`models` 支持：正则（`~r/^claude-/`）、字符串列表（`["gpt-4o"]`）、`:default`（兜底）。

# `provider_entry`

```elixir
@type provider_entry() :: {module(), keyword()}
```

# `t`

```elixir
@type t() :: %CMDC.Config{
  data_dir: String.t(),
  default_model: String.t(),
  default_tools: [module()],
  provider: module() | nil,
  provider_opts: keyword(),
  providers: [provider_entry()]
}
```

# `data_dir`

```elixir
@spec data_dir(t()) :: String.t()
```

数据目录的展开绝对路径。

# `default_data_dir`

```elixir
@spec default_data_dir() :: String.t()
```

返回当前平台的默认数据目录（`~/.cmdc`）。

# `default_model_id`

```elixir
@spec default_model_id(t()) :: String.t()
```

从 default_model 字符串中提取纯模型 ID（去除 provider 前缀）。

# `ensure_dirs!`

```elixir
@spec ensure_dirs!(t()) :: :ok
```

确保数据目录树存在（目录不存在时自动创建）。

# `logs_dir`

```elixir
@spec logs_dir(t()) :: String.t()
```

日志目录路径。

# `new`

```elixir
@spec new(keyword() | map()) ::
  {:ok, t()} | {:error, NimbleOptions.ValidationError.t()}
```

从 Application env + 可选覆盖构建 Config struct，返回 `{:ok, t()}` 或 `{:error, ...}`。

# `new!`

```elixir
@spec new!(keyword() | map()) :: t()
```

从 Application env + 可选覆盖构建 Config struct，校验失败时抛出异常。

## 示例

    iex> CMDC.Config.new!(data_dir: "/tmp/cmdc")
    %CMDC.Config{data_dir: "/tmp/cmdc", ...}

# `resolve_provider`

```elixir
@spec resolve_provider(t(), String.t()) :: provider_entry()
```

根据模型名解析对应的 Provider 模块和 opts。

路由规则：
1. 若配置了 `providers`，按 `models` 规则查找第一个匹配项
2. 若无匹配，返回 `:default` 标记的兜底接入点
3. 均未匹配，回退到 `provider` + `provider_opts` 单 Provider 配置

# `sessions_dir`

```elixir
@spec sessions_dir(t()) :: String.t()
```

会话存储目录路径。

---

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