# 機能設計書 14-WebSearch ツール

## 概要

本ドキュメントは、OpenCodeのWebSearch ツール機能の設計仕様を定義する。WebSearch ツールは、Exa AIのMCP APIを使用してWeb検索を行い、最新の情報をエージェントに提供する機能を担う。

### 本機能の処理概要

WebSearch ツールは、指定されたクエリでWeb検索を実行し、検索結果のコンテンツをエージェントに返却する機能である。ライブクロール機能やフルテキスト検索により、最新かつ包括的な情報を取得できる。

**業務上の目的・背景**：AIエージェントの知識には限界があり、最新の情報やドキュメント、ニュースなどにアクセスするためにはWeb検索機能が必要である。本ツールにより、エージェントは知識カットオフ以降の情報や、特定のトピックについての最新情報を取得できる。

**機能の利用シーン**：
- 最新のライブラリドキュメントの検索
- 技術的な問題の解決策検索
- 最新ニュースや動向の調査
- APIの使用方法の検索
- エラーメッセージの解決策検索

**主要な処理内容**：
1. 検索権限の確認
2. MCPリクエストの構築
3. Exa AI APIへのリクエスト送信
4. SSEレスポンスの解析
5. 検索結果の返却

**関連システム・外部連携**：
- Exa AI MCP API（https://mcp.exa.ai/mcp）：Web検索エンジン

**権限による制御**：
- `websearch`権限が必要

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 26 | セッション | 補助機能 | WebSearchコンポーネントによるWeb検索結果表示 |

## 機能種別

外部API連携 / データ検索

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| query | string | Yes | Web検索クエリ | 空文字列不可 |
| numResults | number | No | 返却する検索結果数（デフォルト: 8） | 正の整数 |
| livecrawl | enum | No | ライブクロールモード: "fallback"（デフォルト）または"preferred" | "fallback" \| "preferred" |
| type | enum | No | 検索タイプ: "auto"（デフォルト）、"fast"、"deep" | "auto" \| "fast" \| "deep" |
| contextMaxCharacters | number | No | LLM向けに最適化されたコンテキストの最大文字数（デフォルト: 10000） | 正の整数 |

### 入力データソース

- ユーザー入力（検索クエリ）
- 実行コンテキスト（セッションID、メッセージID等）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| title | string | "Web search: {クエリ}" |
| output | string | 検索結果のテキスト内容 |
| metadata | object | 空オブジェクト |

### 出力先

- エージェントへのレスポンス（ツール実行結果）

## 処理フロー

### 処理シーケンス

```
1. Web検索権限確認
   └─ ctx.askでwebsearch権限を要求

2. MCPリクエスト構築
   └─ JSON-RPC 2.0形式でリクエストを構築

3. タイムアウト設定
   └─ 25秒のタイムアウトを設定

4. Exa AI APIリクエスト
   └─ POSTリクエストを送信

5. レスポンス解析
   └─ SSE形式のレスポンスを解析

6. 結果返却
   └─ 検索結果または"No results"メッセージを返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[Web検索権限確認]
    B --> C[MCPリクエスト構築]
    C --> D[タイムアウト設定 25秒]
    D --> E[Exa AI APIリクエスト]
    E --> F{レスポンスOK?}
    F -->|No| ERROR1[エラー: Search error]
    F -->|Yes| G[SSEレスポンス解析]
    G --> H{結果あり?}
    H -->|Yes| I[検索結果返却]
    H -->|No| J[No results返却]
    I --> OUTPUT[結果返却]
    J --> OUTPUT

    E -->|タイムアウト| ERROR2[エラー: Search request timed out]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | デフォルト結果数 | 検索結果はデフォルト8件 | numResults未指定時 |
| BR-02 | デフォルト検索タイプ | 検索タイプはデフォルト"auto" | type未指定時 |
| BR-03 | デフォルトクロールモード | ライブクロールはデフォルト"fallback" | livecrawl未指定時 |
| BR-04 | タイムアウト | リクエストは25秒でタイムアウト | 常時 |
| BR-05 | 年号置換 | ツール説明文内の{{year}}は現在年に置換 | 常時 |

### 計算ロジック

**MCPリクエスト構築**：
```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "web_search_exa",
    "arguments": {
      "query": "<検索クエリ>",
      "type": "auto|fast|deep",
      "numResults": 8,
      "livecrawl": "fallback|preferred",
      "contextMaxCharacters": 10000
    }
  }
}
```

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

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

本機能は外部APIとの通信のみを行い、データベースへの直接的な操作は行わない。

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | データベース操作なし |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | TimeoutError | 25秒以内にレスポンスがない | クエリを簡潔にする、再試行する |
| - | APIError | Exa AI APIがエラーを返却 | クエリを修正する、時間をおいて再試行 |
| - | PermissionError | websearch権限がない | 適切な権限を付与 |

### リトライ仕様

本機能はリトライ処理を行わない。エラー発生時は即座にエラーを返却する。

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

外部API通信のため、トランザクション管理は行わない。

## パフォーマンス要件

- タイムアウト: 25秒
- AbortSignalによるキャンセル対応

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

- websearch権限による実行制御
- 外部APIへの通信はHTTPSで暗号化

## 備考

- Exa AI MCPは認証不要のパブリックAPIを使用
- レスポンスはSSE（Server-Sent Events）形式
- 検索時は現在の年を考慮してクエリを構築することが推奨される

---

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

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

### 推奨読解順序

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

ツールの入出力パラメータとAPIリクエスト/レスポンスの構造を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | websearch.ts | `packages/opencode/src/tool/websearch.ts` | McpSearchRequest型（14-28行目）とMcpSearchResponse型（30-38行目）を確認 |

**読解のコツ**: JSON-RPC 2.0形式のMCPプロトコルを使用している。toolsのnameが"web_search_exa"であることに注目。

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

WebSearch ツールの本体実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | websearch.ts | `packages/opencode/src/tool/websearch.ts` | execute関数の全体フロー（65-148行目） |

**主要処理フロー**:
1. **40-44行目**: ツール定義（descriptionに年号置換あり）
2. **45-64行目**: パラメータスキーマ定義
3. **66-77行目**: 権限確認
4. **79-93行目**: MCPリクエスト構築
5. **95-108行目**: APIリクエスト送信
6. **119-132行目**: SSEレスポンス解析
7. **134-147行目**: エラーハンドリング

#### Step 3: タイムアウト処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | abort.ts | `packages/opencode/src/util/abort.ts` | abortAfterAny関数（28-35行目） |

**主要処理フロー**:
- **95行目**: 25秒タイムアウトとctx.abortの組み合わせ

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

```
WebSearchTool.execute
    │
    ├─ ctx.ask (websearch権限要求)
    │
    ├─ abortAfterAny (タイムアウト設定)
    │      └─ abortAfter (内部タイマー)
    │
    └─ fetch (Exa AI APIリクエスト)
           └─ SSEレスポンス解析
```

### データフロー図

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

query ────────────────────▶ クエリ検証
                                │
numResults ───────────────────▶│
                                │
livecrawl ────────────────────▶│ MCPリクエスト構築
                                │
type ─────────────────────────▶│
                                │
contextMaxCharacters ─────────▶│
                                │
                                ▼
                           Exa AI API
                           (mcp.exa.ai)
                                │
                                ▼
                           SSEレスポンス解析
                                │
                                ▼
                           結果返却 ─────────▶ title
                                              output
                                              metadata
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| websearch.ts | `packages/opencode/src/tool/websearch.ts` | ソース | WebSearch ツール本体 |
| websearch.txt | `packages/opencode/src/tool/websearch.txt` | テンプレート | ツール説明文 |
| tool.ts | `packages/opencode/src/tool/tool.ts` | ソース | ツール基盤定義 |
| abort.ts | `packages/opencode/src/util/abort.ts` | ソース | タイムアウトユーティリティ |
