# 機能設計書 90-Copilotメッセージ

## 概要

本ドキュメントは、Chatwoot Captain Copilotのメッセージ管理機能の設計を記載する。Copilotスレッド内でのユーザーとAIのメッセージを管理するEnterprise機能である。

### 本機能の処理概要

Copilotメッセージ機能は、Copilotスレッド内でのメッセージの作成・取得を管理する機能である。

**業務上の目的・背景**：Copilotスレッドが作成された後、エージェントはスレッド内で継続的にAIと対話を行う。Copilotメッセージ機能により、スレッド内のメッセージ履歴を取得し、新しい質問を送信し、AIからの応答を受け取ることができる。

**機能の利用シーン**：
- エージェントがCopilotスレッド内でメッセージを送信する際
- スレッド内のメッセージ履歴を取得する際
- AIからの応答をリアルタイムで受信する際

**主要な処理内容**：
1. スレッド内メッセージ一覧の取得
2. 新規メッセージの作成
3. AI応答ジョブのキュー追加
4. WebSocketによるリアルタイム通知

**関連システム・外部連携**：Captain Copilot ChatService、LLMプロバイダー、WebSocket通知との連携。

**権限による制御**：ログインユーザーのみがアクセス可能。自分のスレッド内メッセージのみ参照・作成可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | Copilotパネル | 主機能 | Copilotとの対話メッセージ |

## 機能種別

CRUD操作（Create/Read） / AI連携

## 入力仕様

### 入力パラメータ（メッセージ作成）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| copilot_thread_id | Integer | Yes | スレッドID | 存在するスレッド |
| message | String | Yes | メッセージ内容 | presence: true |
| conversation_id | Integer | No | 閲覧中の会話ID | 存在する会話 |

### 入力パラメータ（一覧取得）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| copilot_thread_id | Integer | Yes | スレッドID | 存在するスレッド |
| page | Integer | No | ページ番号 | デフォルト: 1 |

### 入力データソース

- Copilotパネルからのユーザー入力

## 出力仕様

### 出力データ（メッセージ一覧）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | BigInt | メッセージID |
| message | JSONB | メッセージ内容 |
| message.content | String | テキスト内容 |
| message.reasoning | String | AI推論過程（オプション） |
| message.function_name | String | 呼び出し関数名（オプション） |
| message.reply_suggestion | String | 返信提案（オプション） |
| message_type | String | user / assistant / assistant_thinking |
| created_at | DateTime | 作成日時 |
| copilot_thread | Object | スレッド情報 |

### 出力データ（メッセージ作成）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | BigInt | メッセージID |
| message | JSONB | メッセージ内容 |
| message_type | String | user |
| created_at | DateTime | 作成日時 |

### 出力先

- JSON APIレスポンス
- WebSocket（COPILOT_MESSAGE_CREATED）

## 処理フロー

### 処理シーケンス

```
1. メッセージ一覧取得（index）
   └─ スレッド存在確認（ユーザー条件）
   └─ メッセージを作成日時昇順で取得
   └─ ページネーション適用
2. メッセージ作成（create）
   └─ スレッド存在確認（ユーザー条件）
   └─ CopilotMessage作成（message_type=user）
   └─ AI応答ジョブキュー追加
```

### フローチャート

```mermaid
flowchart TD
    A[Copilotパネル] --> B[GET /captain/copilot_threads/:id/copilot_messages]
    B --> C[CopilotMessagesController#index]
    C --> D[set_copilot_thread]
    D --> E{スレッド存在?<br/>ユーザー条件}
    E -->|No| F[404 NotFound]
    E -->|Yes| G[copilot_messages取得<br/>order: asc]
    G --> H[JSON応答]

    I[メッセージ送信] --> J[POST /captain/copilot_threads/:id/copilot_messages]
    J --> K[CopilotMessagesController#create]
    K --> L[set_copilot_thread]
    L --> M{スレッド存在?<br/>ユーザー条件}
    M -->|No| N[404 NotFound]
    M -->|Yes| O[CopilotMessage.create!<br/>type: user]
    O --> P[enqueue_response_job]
    P --> Q[JSON応答]

    P --> R[ResponseJob<br/>非同期処理]
    R --> S[ChatService.generate_response]
    S --> T[CopilotMessage.create!<br/>type: assistant]
    T --> U[WebSocket配信<br/>COPILOT_MESSAGE_CREATED]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-90-01 | スレッド所有者 | 自分のスレッド内メッセージのみアクセス可能 | 全操作 |
| BR-90-02 | メッセージ構造 | messageはcontent, reasoning, function_name, reply_suggestionのみ許可 | 作成時 |
| BR-90-03 | 自動account設定 | account_idはスレッドから自動取得 | 作成時 |
| BR-90-04 | リアルタイム通知 | メッセージ作成後WebSocketで通知 | 作成後 |
| BR-90-05 | 非同期AI応答 | AI応答はジョブキューで非同期処理 | メッセージ作成後 |

### 計算ロジック

該当なし

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

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 一覧取得 | copilot_messages | SELECT | スレッド内メッセージ取得 |
| 作成 | copilot_messages | INSERT | ユーザーメッセージ作成 |
| 作成 | copilot_messages | INSERT | AI応答メッセージ作成（非同期） |

### テーブル別操作詳細

#### copilot_messages

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | copilot_thread_id | スレッドID | 取得条件 |
| SELECT | - | order(created_at: :asc) | 作成日時昇順 |
| INSERT | copilot_thread_id | パスパラメータ | 必須 |
| INSERT | message | {content: メッセージ} | JSONB |
| INSERT | message_type | user | enum |
| INSERT | account_id | 自動設定 | スレッドから取得 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 404 | NotFound | スレッドが存在しないまたは他ユーザーのスレッド | スレッドIDを確認 |
| 422 | ValidationError | メッセージ形式不正 | メッセージ内容を確認 |

### リトライ仕様

AI応答ジョブはSidekiq標準のリトライ機能に従う

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

メッセージ作成は単一レコード操作のため、暗黙的トランザクション

## パフォーマンス要件

- メッセージ一覧は1000件/ページ（スレッド内全履歴取得想定）
- includes(:copilot_thread)でN+1防止

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

- ユーザー認証必須
- スレッド所有者のみアクセス可能（find_by!(id:, user:)）
- messageの属性制限（validate_message_attributes）

## 備考

- Enterprise版機能
- WebSocket（COPILOT_MESSAGE_CREATED）でリアルタイム通知
- AI応答は非同期ジョブで処理
- message_type: assistant_thinkingは中間状態（推論中）

---

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

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

### 推奨読解順序

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

まず、CopilotMessageのデータモデルを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | copilot_message.rb | `enterprise/app/models/copilot_message.rb` | モデル定義 |

**読解のコツ**:
- **18-20行目**: belongs_to関連（copilot_thread, account）
- **22行目**: message_type enum（user, assistant, assistant_thinking）
- **24-27行目**: バリデーション（message_type, message必須、account自動設定）
- **28行目**: after_create_commit :broadcast_messageでWebSocket通知
- **30-38行目**: push_event_dataでWebSocket用データ生成
- **40-48行目**: enqueue_response_jobでResponseJobキュー追加
- **60-66行目**: validate_message_attributesで許可キー制限

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | copilot_messages_controller.rb | `enterprise/app/controllers/api/v1/accounts/captain/copilot_messages_controller.rb` | CRUD操作 |

**主要処理フロー**:
- **4-10行目**: indexでメッセージ取得（作成日時昇順、1000件/ページ）
- **12-18行目**: createでメッセージ作成とResponseJobキュー追加
- **22-27行目**: set_copilot_threadでスレッド取得（ユーザー条件）

#### Step 3: AI応答の仕組みを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | chat_service.rb | `enterprise/app/services/captain/copilot/chat_service.rb` | Copilot ChatService |

**主要処理フロー**:
- **6-19行目**: initializeでアシスタント、ユーザー、ツール初期化
- **22-33行目**: generate_responseでLLM呼び出しと使用量インクリメント
- **62-75行目**: build_toolsで利用可能ツール設定
- **115-122行目**: persist_messageでスレッドにメッセージ保存

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

```
CopilotMessagesController
    │
    ├─ index
    │      └─ @copilot_thread.copilot_messages
    │              └─ order(created_at: :asc)
    │              └─ page().per(1000)
    │
    └─ create
           │
           ├─ copilot_messages.create!
           │      └─ message_type: :user
           │      └─ after_create_commit: broadcast_message
           │              └─ dispatcher.dispatch(COPILOT_MESSAGE_CREATED)
           │
           └─ enqueue_response_job
                  └─ Captain::Copilot::ResponseJob.perform_later
                         │
                         └─ ChatService.new(assistant, config)
                                │
                                ├─ build_messages
                                │      ├─ system_message
                                │      ├─ previous_history
                                │      └─ current_viewing_history
                                │
                                └─ generate_response(input)
                                       │
                                       ├─ request_chat_completion
                                       │      └─ LLM API呼び出し
                                       │
                                       └─ persist_message
                                              └─ copilot_messages.create!
                                                     └─ message_type: :assistant
```

### データフロー図

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

message ───▶ CopilotMessagesController ───▶ CopilotMessage (user)
copilot_thread_id        │                        │
conversation_id          └─ create                └─ WebSocket配信
                                │
                                └─ ResponseJob (非同期)
                                       │
                                       └─ ChatService
                                              │
                                              ├─ 履歴構築
                                              │      ├─ システムメッセージ
                                              │      ├─ 過去履歴
                                              │      └─ 現在閲覧中会話
                                              │
                                              └─ LLM API
                                                     │
                                                     └─ CopilotMessage (assistant)
                                                            │
                                                            └─ WebSocket配信
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| copilot_messages_controller.rb | `enterprise/app/controllers/api/v1/accounts/captain/copilot_messages_controller.rb` | コントローラー | CRUD API |
| copilot_message.rb | `enterprise/app/models/copilot_message.rb` | モデル | メッセージデータモデル |
| copilot_thread.rb | `enterprise/app/models/copilot_thread.rb` | モデル | スレッドデータモデル |
| chat_service.rb | `enterprise/app/services/captain/copilot/chat_service.rb` | サービス | Copilot ChatService |
| response_job.rb | `enterprise/app/jobs/captain/copilot/response_job.rb` | ジョブ | 非同期AI応答処理 |
| base_ai_service.rb | `lib/llm/base_ai_service.rb` | ライブラリ | LLM API基底クラス |
