# 機能設計書 29-モデル管理

## 概要

本ドキュメントは、OpenCodeにおけるモデル管理機能の設計を定義する。モデル管理は、各AIプロバイダーが提供するモデルの検出、能力情報、コスト情報、バリアント管理を行う機能である。

### 本機能の処理概要

モデル管理機能は、AIモデルのメタデータ（名前、能力、コスト、制限等）を管理し、ユーザーやシステムが適切なモデルを選択できるようにする機能である。

**業務上の目的・背景**：多数のAIモデルの中から、タスクに適したモデルを選択できるようにする。コスト、性能、能力の観点から最適なモデルを判断するための情報を提供する。

**機能の利用シーン**：ユーザーがモデルを選択する際、デフォルトモデルを決定する際、モデルの能力（画像入力、推論等）を確認する際、コスト見積もりを行う際に利用される。

**主要な処理内容**：
1. models.devからのモデル情報取得とキャッシュ
2. モデルの能力情報（温度、推論、添付ファイル、ツール呼び出し等）の管理
3. モデルのコスト情報の管理
4. モデルのバリアント（高温度、拡張思考等）の管理
5. デフォルトモデルの選択
6. 小型モデル（サブタスク用）の選択

**関連システム・外部連携**：models.dev（モデルカタログAPI）。

**権限による制御**：設定ファイルでモデルのwhitelist/blacklistを指定可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 14 | ワークスペースダッシュボード | 補助機能 | モデル選択セクションの表示 |

## 機能種別

データ管理 / キャッシュ処理

## 入力仕様

### 入力パラメータ

#### モデル取得

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| providerID | string | Yes | プロバイダー識別子 | 存在するプロバイダーID |
| modelID | string | Yes | モデル識別子 | 存在するモデルID |

#### モデルパース

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| model | string | Yes | "providerID/modelID"形式 | スラッシュ区切り |

### 入力データソース

- models.dev API（https://models.dev/api.json）
- ローカルキャッシュ（cache/models.json）
- 設定ファイル（opencode.json）

## 出力仕様

### 出力データ

#### Provider.Model

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | string | モデルID |
| providerID | string | プロバイダーID |
| name | string | 表示名 |
| family | string? | モデルファミリー |
| api.id | string | API用モデルID |
| api.url | string | APIエンドポイント |
| api.npm | string | SDKパッケージ名 |
| capabilities | object | モデル能力 |
| cost | object | 料金情報 |
| limit | object | 制限情報 |
| status | string | ステータス（alpha/beta/deprecated/active） |
| options | object | モデル固有オプション |
| headers | object | カスタムヘッダー |
| release_date | string | リリース日 |
| variants | object | バリアント定義 |

#### capabilities

| 項目名 | 型 | 説明 |
|--------|-----|------|
| temperature | boolean | 温度パラメータ対応 |
| reasoning | boolean | 推論（思考）対応 |
| attachment | boolean | ファイル添付対応 |
| toolcall | boolean | ツール呼び出し対応 |
| input | object | 入力モダリティ（text/audio/image/video/pdf） |
| output | object | 出力モダリティ |
| interleaved | boolean \| object | インターリーブ思考対応 |

### 出力先

- メモリ内キャッシュ
- state.providers[providerID].models

## 処理フロー

### 処理シーケンス

```
1. models.dev取得（ModelsDev.get）
   ├─ ローカルキャッシュ確認
   ├─ スナップショット確認（ビルド時埋め込み）
   └─ API呼び出し（フォールバック）

2. モデル変換（fromModelsDevModel）
   ├─ 基本情報のマッピング
   ├─ 能力情報の変換
   ├─ コスト情報の変換
   └─ バリアントの生成

3. デフォルトモデル選択（defaultModel）
   ├─ 設定ファイルのmodel確認
   ├─ 最近使用したモデルの確認
   └─ プロバイダーのモデルをソート

4. 小型モデル選択（getSmallModel）
   ├─ 設定ファイルのsmall_model確認
   ├─ 優先順位リストから検索
   └─ opencode/gpt-5-nanoへのフォールバック

5. モデルソート（sort）
   └─ 優先順位に基づくソート（gpt-5, claude-sonnet-4等）
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{ローカルキャッシュあり?}
    B -->|Yes| C[キャッシュ読み込み]
    B -->|No| D{スナップショットあり?}
    D -->|Yes| E[スナップショット使用]
    D -->|No| F[API呼び出し]
    C --> G[モデル変換]
    E --> G
    F --> G
    G --> H[設定ファイルマージ]
    H --> I[バリアント生成]
    I --> J[モデル一覧完成]

    K[defaultModel呼び出し] --> L{config.modelあり?}
    L -->|Yes| M[parseModelで解析]
    L -->|No| N{最近使用あり?}
    N -->|Yes| O[最近使用を返却]
    N -->|No| P[ソートして最初を返却]

    Q[getSmallModel呼び出し] --> R{config.small_modelあり?}
    R -->|Yes| S[parseModelで解析]
    R -->|No| T[優先順位リストから検索]
    T --> U{見つかった?}
    U -->|Yes| V[モデル返却]
    U -->|No| W[opencode/gpt-5-nano]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-29-01 | models.dev更新 | 1時間ごとにバックグラウンドで更新 | アプリ起動中 |
| BR-29-02 | ステータスフィルタ | alpha/deprecatedモデルはデフォルトで除外 | モデル一覧生成時 |
| BR-29-03 | デフォルトモデル優先順位 | gpt-5 > claude-sonnet-4 > big-pickle > gemini-3-pro | ソート時 |
| BR-29-04 | 小型モデル優先順位 | claude-haiku-4-5 > gemini-3-flash > gpt-5-nano | 小型モデル選択時 |
| BR-29-05 | バリアント生成 | ProviderTransform.variantsで自動生成 | モデル変換時 |

### 計算ロジック

モデルソートの優先順位:
```typescript
const priority = ["gpt-5", "claude-sonnet-4", "big-pickle", "gemini-3-pro"]
// 優先順位高いものほど先に
// "latest"を含むものを優先
// 残りはID降順
```

## データベース操作仕様

データベース操作は行わない（ファイルキャッシュとメモリ管理）。

### ファイル操作

| 操作 | ファイル | 操作種別 | 概要 |
|-----|---------|---------|------|
| キャッシュ読み込み | cache/models.json | READ | モデル情報のキャッシュ |
| キャッシュ更新 | cache/models.json | WRITE | API取得結果の保存 |
| 最近使用読み込み | state/model.json | READ | 最近使用したモデル |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | API取得失敗 | models.devへの接続失敗 | キャッシュ/スナップショット使用 |
| ProviderModelNotFoundError | NamedError | モデルが存在しない | fuzzysortでサジェスト |

### リトライ仕様

models.dev取得時のリトライは実装されていない（10秒タイムアウト）。

## トランザクション仕様

トランザクションは不要。

## パフォーマンス要件

- models.dev更新は1時間ごと（バックグラウンド）
- キャッシュ読み込みは100ms以内
- モデル変換は1ms以内

## セキュリティ考慮事項

- models.devは信頼できるソースとして扱う
- カスタムAPIエンドポイントは設定ファイルで指定可能（注意が必要）

## 備考

- バリアントはモデル固有の設定バリエーション（高温度、拡張思考等）
- OPENCODE_MODELS_URLフラグでmodels.devのURLをオーバーライド可能
- OPENCODE_DISABLE_MODELS_FETCHでAPI取得を無効化可能

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | provider.ts | `packages/opencode/src/provider/provider.ts` | Provider.Model zodスキーマ（593-662行目） |
| 1-2 | models.ts | `packages/opencode/src/provider/models.ts` | ModelsDev.Model定義（18-71行目） |

**読解のコツ**: Provider.Modelはアプリ内部で使用する形式、ModelsDev.Modelはmodels.devからの生データ形式。変換ロジックを理解する。

#### Step 2: データ取得を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | models.ts | `packages/opencode/src/provider/models.ts` | ModelsDev.get関数（101-104行目） |
| 2-2 | models.ts | `packages/opencode/src/provider/models.ts` | ModelsDev.Data lazy関数（88-99行目） |
| 2-3 | models.ts | `packages/opencode/src/provider/models.ts` | ModelsDev.refresh関数（106-121行目） |

**主要処理フロー**:
- **88-99行目**: キャッシュ → スナップショット → APIの順で取得
- **106-121行目**: バックグラウンドでの更新処理

#### Step 3: モデル変換を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | provider.ts | `packages/opencode/src/provider/provider.ts` | fromModelsDevModel関数（679-744行目） |
| 3-2 | provider.ts | `packages/opencode/src/provider/provider.ts` | fromModelsDevProvider関数（746-755行目） |

#### Step 4: モデル選択を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | provider.ts | `packages/opencode/src/provider/provider.ts` | Provider.defaultModel関数（1288-1313行目） |
| 4-2 | provider.ts | `packages/opencode/src/provider/provider.ts` | Provider.getSmallModel関数（1212-1276行目） |
| 4-3 | provider.ts | `packages/opencode/src/provider/provider.ts` | Provider.sort関数（1279-1286行目） |
| 4-4 | provider.ts | `packages/opencode/src/provider/provider.ts` | Provider.parseModel関数（1315-1320行目） |

### プログラム呼び出し階層図

```
ModelsDev.get()
    │
    └─ ModelsDev.Data() [lazy]
           │
           ├─ Filesystem.readJson(cache/models.json)
           │
           ├─ import("./models-snapshot") [フォールバック]
           │
           └─ fetch(models.dev/api.json) [フォールバック]

fromModelsDevModel(provider, model)
    │
    ├─ 基本情報マッピング
    │
    ├─ 能力情報変換
    │      └─ modalities → input/output
    │
    ├─ コスト情報変換
    │      └─ experimentalOver200K対応
    │
    └─ ProviderTransform.variants()
           └─ バリアント生成

Provider.defaultModel()
    │
    ├─ Config.get().model
    │      └─ parseModel()
    │
    ├─ Filesystem.readJson(state/model.json)
    │      └─ recent[0]
    │
    └─ Provider.sort()
           └─ 優先順位ソート
```

### データフロー図

```
[入力]                    [処理]                         [出力]

models.dev ─────┐                                    ┌─> ModelsDev.Provider[]
                │                                    │
キャッシュ ─────┼──▶ ModelsDev.Data() ───────────────┤
                │                                    │
スナップショット ┘                                    │
                                                     │
ModelsDev.Model ▶ fromModelsDevModel() ─────────────▶ Provider.Model
                        │
                        ├─ 能力変換
                        ├─ コスト変換
                        └─ バリアント生成

config.model ───┐
                ├──▶ Provider.defaultModel() ───────▶ {providerID, modelID}
recent[] ───────┤
                │
providers ──────┘

providerID ────▶ Provider.getSmallModel() ─────────▶ Provider.Model
                        │
                        ├─ config.small_model
                        ├─ 優先順位リスト
                        └─ opencode/gpt-5-nano
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| provider.ts | `packages/opencode/src/provider/provider.ts` | ソース | Provider.Model定義、変換関数、選択関数 |
| models.ts | `packages/opencode/src/provider/models.ts` | ソース | models.devからのデータ取得 |
| transform.ts | `packages/opencode/src/provider/transform.ts` | ソース | バリアント生成ロジック |
| config.ts | `packages/opencode/src/config/config.ts` | ソース | モデル設定の読み込み |
