# 機能設計書 15-WebFetch ツール

## 概要

本ドキュメントは、OpenCodeのWebFetch ツール機能の設計仕様を定義する。WebFetch ツールは、指定されたURLからコンテンツを取得し、指定されたフォーマット（Markdown、テキスト、HTML）でエージェントに提供する機能を担う。

### 本機能の処理概要

WebFetch ツールは、URLを指定してWebコンテンツを取得し、HTMLをMarkdownやプレーンテキストに変換して返却する機能である。画像の取得にも対応し、Base64エンコードで返却する。

**業務上の目的・背景**：AIエージェントがWeb上のドキュメント、API仕様書、ブログ記事などの内容を参照するために、URLからコンテンツを取得する機能が必要である。本ツールにより、エージェントは外部のWebリソースを読み取り、コンテキストとして活用できる。

**機能の利用シーン**：
- ドキュメントページの内容取得
- API仕様書の参照
- ブログ記事やチュートリアルの読み取り
- 画像ファイルの取得
- GitHub等のコードリポジトリページの参照

**主要な処理内容**：
1. URLバリデーション
2. 取得権限の確認
3. HTTPリクエストの送信（Cloudflare対応）
4. Content-Typeに応じた処理分岐
5. HTMLからMarkdown/テキストへの変換
6. 結果の返却

**関連システム・外部連携**：
- TurndownService：HTML→Markdown変換
- HTMLRewriter：HTML→テキスト変換

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

## 関連画面

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

## 機能種別

外部API連携 / データ取得

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| url | string | Yes | 取得対象のURL | http://またはhttps://で始まること |
| format | enum | No | 出力フォーマット: "markdown"（デフォルト）、"text"、"html" | "markdown" \| "text" \| "html" |
| timeout | number | No | タイムアウト秒数（最大120秒） | 正の整数、最大120 |

### 入力データソース

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

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| title | string | "{URL} ({Content-Type})" |
| output | string | 取得したコンテンツ（指定フォーマット） |
| metadata | object | 空オブジェクト |
| attachments | array | 画像の場合のBase64エンコードデータ |

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. URLバリデーション
   └─ http://またはhttps://で始まることを確認

2. 取得権限確認
   └─ ctx.askでwebfetch権限を要求

3. タイムアウト設定
   └─ デフォルト30秒、最大120秒

4. HTTPリクエスト
   └─ Acceptヘッダーを設定してfetch

5. Cloudflare対策
   └─ 403 + cf-mitigatedの場合、正直なUAで再試行

6. Content-Type判定
   └─ 画像/テキスト/HTMLの判定

7. コンテンツ変換
   └─ format指定に応じた変換処理

8. 結果返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{URLバリデーション}
    B -->|無効| ERROR1[エラー: URL must start with http/https]
    B -->|有効| C[取得権限確認]
    C --> D[タイムアウト設定]
    D --> E[HTTPリクエスト]
    E --> F{403 + cf-mitigated?}
    F -->|Yes| G[正直なUAで再試行]
    F -->|No| H{レスポンスOK?}
    G --> H
    H -->|No| ERROR2[エラー: Request failed]
    H -->|Yes| I{サイズ確認}
    I -->|5MB超| ERROR3[エラー: Response too large]
    I -->|OK| J{Content-Type判定}
    J -->|画像| K[Base64エンコード]
    J -->|HTML + markdown| L[TurndownでMarkdown変換]
    J -->|HTML + text| M[HTMLRewriterでテキスト抽出]
    J -->|その他| N[そのまま返却]
    K --> OUTPUT[結果返却]
    L --> OUTPUT
    M --> OUTPUT
    N --> OUTPUT
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | デフォルトフォーマット | 出力はデフォルトでMarkdown | format未指定時 |
| BR-02 | デフォルトタイムアウト | タイムアウトはデフォルト30秒 | timeout未指定時 |
| BR-03 | 最大タイムアウト | タイムアウトは最大120秒（2分） | 常時 |
| BR-04 | レスポンスサイズ制限 | レスポンスは最大5MB | 常時 |
| BR-05 | 画像除外 | SVGとvnd.fastbidsheetは画像として扱わない | image/で始まるMIMEタイプ |
| BR-06 | Cloudflare対策 | 403 + cf-mitigated の場合、"opencode" UAで再試行 | Cloudflare保護サイト |

### 計算ロジック

**Acceptヘッダー構築（format別）**：
- markdown: `text/markdown;q=1.0, text/x-markdown;q=0.9, text/plain;q=0.8, text/html;q=0.7, */*;q=0.1`
- text: `text/plain;q=1.0, text/markdown;q=0.9, text/html;q=0.8, */*;q=0.1`
- html: `text/html;q=1.0, application/xhtml+xml;q=0.9, text/plain;q=0.8, text/markdown;q=0.7, */*;q=0.1`

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

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

本機能は外部URLへのHTTPリクエストのみを行い、データベースへの直接的な操作は行わない。

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ValidationError | URLがhttp/httpsで始まらない | 正しいURLを指定 |
| - | HTTPError | リクエストが失敗 | URLを確認、時間をおいて再試行 |
| - | SizeError | レスポンスが5MBを超過 | 小さいリソースを指定 |
| - | TimeoutError | タイムアウト時間内にレスポンスがない | タイムアウト値を増やす |

### リトライ仕様

- Cloudflare bot検出（403 + cf-mitigated）の場合のみ自動再試行
- その他のエラーはリトライせず即座にエラーを返却

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

外部HTTPリクエストのため、トランザクション管理は行わない。

## パフォーマンス要件

- デフォルトタイムアウト: 30秒
- 最大タイムアウト: 120秒（2分）
- 最大レスポンスサイズ: 5MB
- AbortSignalによるキャンセル対応

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

- webfetch権限による実行制御
- HTTPSへの自動アップグレードは行わない（明示的なHTTPも許可）
- User-AgentはChromeを偽装（Cloudflare対策）

## 備考

- 画像ファイルはBase64エンコードされてattachmentsとして返却される
- TurndownServiceでHTML→Markdown変換時、script/style/meta/linkタグは除去される
- HTMLRewriterでテキスト抽出時、script/style/noscript/iframe/object/embedタグ内のテキストはスキップされる

---

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

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

### 推奨読解順序

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

ツールの入出力パラメータを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | webfetch.ts | `packages/opencode/src/tool/webfetch.ts` | パラメータスキーマ（13-20行目）を確認 |

**読解のコツ**: formatのデフォルト値が"markdown"であることに注目。timeoutは秒単位で指定。

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

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

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

**主要処理フロー**:
1. **22-25行目**: URLバリデーション
2. **27-36行目**: 権限確認
3. **38行目**: タイムアウト計算
4. **42-57行目**: Acceptヘッダー構築
5. **65-71行目**: HTTPリクエストとCloudflare対策
6. **79-88行目**: サイズチェック
7. **94-111行目**: 画像処理
8. **116-160行目**: フォーマット別変換処理

#### Step 3: HTML変換処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | webfetch.ts | `packages/opencode/src/tool/webfetch.ts` | extractTextFromHTML関数（164-194行目）、convertHTMLToMarkdown関数（196-206行目） |

**主要処理フロー**:
- **168-189行目**: HTMLRewriterによるテキスト抽出（スクリプト等を除外）
- **197-205行目**: TurndownServiceによるMarkdown変換

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

```
WebFetchTool.execute
    │
    ├─ ctx.ask (webfetch権限要求)
    │
    ├─ abortAfterAny (タイムアウト設定)
    │
    ├─ fetch (HTTPリクエスト)
    │      └─ Cloudflare対策の再試行
    │
    ├─ extractTextFromHTML (テキスト抽出)
    │      └─ HTMLRewriter
    │
    └─ convertHTMLToMarkdown (Markdown変換)
           └─ TurndownService
```

### データフロー図

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

url ──────────────────────▶ URLバリデーション
                                │
format ───────────────────────▶ Acceptヘッダー構築
                                │
timeout ──────────────────────▶ タイムアウト設定
                                │
                                ▼
                           HTTPリクエスト
                                │
                                ▼
                           Content-Type判定
                                │
                    ┌───────────┼───────────┐
                    ▼           ▼           ▼
                  画像        HTML        その他
                    │           │           │
                    ▼           ▼           ▼
               Base64      Markdown/     そのまま
               エンコード   Text変換      返却
                    │           │           │
                    └───────────┼───────────┘
                                ▼
                           結果返却 ─────────▶ title
                                              output
                                              metadata
                                              attachments
```

### 関連ファイル一覧

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