7.7 KiB
WebFetch
URL を HTTP GET してレスポンス本文を取得するツール。静的ページ向け。
基本
WebFetch({ url: "https://example.com/article", timeout: 30 })
- HTML は readability 抽出でクリーンな Markdown に変換されて返る(ナビ・広告・ヘッダー・フッターを除去し、見出し・リスト・テーブル・リンクは保持)
- JSON / XML / プレーンテキストもそのまま取得可能
- リダイレクトは自動で追従
返却テキストは context 節約のため約 10,000 文字で切り詰められる。スペースタスクでは全文(未切り詰め)が source/ に保存されるので、切り詰めが起きると末尾に ... (truncated; full version saved to source/<file>) という案内が付く。全文を読みたいときは保存された source/ のファイルを Read で開けばよい。
いつ使うか
| 状況 | 使うツール |
|---|---|
| 静的 HTML ページ | WebFetch |
| JS で動的レンダリングされる SPA | BrowseWeb |
| ボタン・フォーム操作が必要 | BrowseWeb |
| ファイルダウンロード | DownloadFile |
| 検索結果を一覧で取得 | WebSearch |
WebFetch は軽量で速い。BrowseWeb はブラウザ起動コストがかかるので、できる限り WebFetch を優先する。
クリーン本文抽出(readability)
取得した生 HTML は、記事本文だけを取り出す readability エンジンで処理してから返す。
内部パイプラインは HTML → linkedom で DOM 化 → @mozilla/readability で記事抽出 → turndown(+gfm) で Markdown 化。
- 除去されるもの: ナビゲーション、広告バナー、ヘッダー、フッター、サイドバー等のボイラープレート
- 保持されるもの: 見出し(
#記法)、箇条書き、番号付きリスト、テーブル(GFM 記法)、リンク、コードブロック - 相対リンクは取得 URL を基準に絶対 URL へ変換される
selectorを指定すると、その CSS セレクタにマッチする要素のサブツリーだけをクリーン抽出する(見つからなければページ全体の抽出にフォールバック)
抽出に失敗するページ(記事構造のない LP、JS で本文を生成する SPA、空ページ等)では、
従来の素朴なタグ除去にフォールバックするので WebFetch が失敗扱いになることはない。
本文がほぼ空のときは SPA の可能性が高いので BrowseWeb に切り替える。
全文は source へ、切り詰め版は agent へ
- agent のコンテキストに返るのは約 10,000 文字に切り詰めた版(context 膨張を防ぐため)
- スペースタスクでは、切り詰める前の全文クリーン Markdown が
source/に保存される - 切り詰めが起きた場合、返却テキスト末尾に
... (truncated; full version saved to source/<file>)が付く - 病的に巨大なページ対策として、
source/保存も 2MB で打ち切る(その旨ノートを付す)
レスポンス履歴
各 WebFetch 呼び出しは logs/webfetch-history.jsonl に記録される。後から「どの URL を取得したか」を振り返れる。
スクリーンショット添付(vlmEnabled 時のみ)
ワーカーが vlm=true(主 LLM が画像入力対応)の場合、WebFetch は成功時に Playwright でファーストビュー(1280×1600 viewport)のスクショを撮り、LLM の文脈に image_url として自動添付する。天気・ダッシュボード・地図など、HTML テキスト抽出では情報が欠落しやすいサイトの理解を補う目的。
- 保存先:
logs/webfetch-screenshots/{timestamp}-{url-hash}.png logs/webfetch-history.jsonlの各レコードにscreenshotPathが記録される- Playwright 未インストール・CAPTCHA・タイムアウト等で失敗しても WebFetch 本体は成功扱い(テキストだけ返る)
- 無効化:
config.yamlのtools.webfetch_screenshot: false - タイムアウト:
tools.webfetch_screenshot_timeout_ms(デフォルト 15,000)
SSRF 保護
ローカル/プライベート IP(127.x.x.x, 10.x.x.x, 172.16-31.x.x, 192.168.x.x, ::1, fc00::/7 等)はデフォルトでブロックされる。社内ホストへアクセスする必要がある場合は Settings UI の「SSRF Allowed Hosts」に追加する。
トラブルシューティング
- 本文がほぼ空: SPA で JS レンダリングが必要 → BrowseWeb に切り替え
- タイムアウト:
timeoutパラメータを増やす(デフォルト 30 秒) - 403/404: User-Agent 制限・bot 検出の可能性 → BrowseWeb なら回避できる場合あり
- SSRF blocked: ローカル/プライベート IP に向いている → 設定追加またはターゲット見直し
エラー時のフォールバック方針
WebFetch がエラーを返した場合、以下の原則で BrowseWeb にリトライする:
| エラー | BrowseWeb で再試行すべきか |
|---|---|
| HTTP 403 / 429 | する — bot 検出・レート制限。ブラウザ User-Agent で回避できる可能性 |
| HTTP 502 / 503 / 504 | する — CDN/upstream の一時的エラー。別の HTTP スタックで成功することがある |
| ネットワークエラー / タイムアウト | する — 動的ページが静的 fetch に応答しないケースが多い |
| HTTP 404 / 401 / 410 | しない — 永続的なエラー。URL を見直すべき |
invalid_url |
しない — URL の記述ミス |
ssrf_blocked |
しない — セキュリティ設定。Settings で allowed hosts を追加 |
pdf_blocked |
しない — DownloadFile + ReadPdf の組み合わせを使う |
binary_blocked |
しない — DownloadFile でバイナリ保存する |
| 本文が極端に短い(< 200 chars) | する — SPA の空シェルを取得した可能性が高い |
Just a moment... 等 Cloudflare challenge |
する — ブラウザで JS challenge を通過できる |
リトライ時は同じ URL を BrowseWeb({ url: "..." }) に渡すだけでよい。BrowseWeb はジョブ内で Cookie・セッションを保持するので、複数回呼んでもログイン状態は引き継がれる。
バイナリの扱い
WebFetch は取得 body の先頭 8KB を sniff し(magic byte / NUL / 不正 UTF-8 / 制御文字比率)、
バイナリと判定したらコンテキストに展開せずブロックする。Content-Type が欠落・詐称
(例: .xls を text/plain)していても実バイトで検出する。バイナリを処理したい場合は
DownloadFile で input/ に保存し、ReadExcel / ReadPdf 等を使う。テキスト body は
5MB で打ち切られる(末尾に [truncated: body exceeded 5MB])。
ソースライブラリへの蓄積(スペースタスク)
スペースのタスクで WebFetch がページ本文を取得すると、クリーン抽出した全文 Markdown(agent への
返却で切り詰める前のもの)が source/ に保存され、出典メタ(URL・タイトル・取得日時・サイズ)が
source/index.jsonl に追記される。
これにより「そのスペースのソース(資料)」が自動で溜まり、後から追加調査やグラウンディングに使える。
同一 URL は重複保存しない(既に index にあればスキップ)。スペース文脈でないタスク
(ephemeral / gitea issue 等)では従来どおり蓄積しない。logs/raw/ への生データ保存は従来どおり。
BrowseWeb(ブラウザ閲覧)や DownloadFile(section: "source")も同じ source/index.jsonl に合流する。